Zrobiłem podklasę UIView
, która ma stałą ramkę. Czy mogę po prostu zastąpić init
zamiast initWithFrame:
? Np.:
- (id)init {
if ((self = [super initWithFrame:[[UIScreen mainScreen] bounds]])) {
self.backgroundColor = [UIColor clearColor];
}
return self;
}
Dokumentacja Xcode dla -initWithFrame:
mówi: „Jeśli tworzysz obiekt widoku programowo, ta metoda jest wyznaczonym inicjatorem dla klasy UIView
. Podklasy mogą przesłonić tę metodę, aby wykonać dowolną niestandardową inicjalizację, ale muszą wywołać super
na początku ich implementacji."
Co oznacza „wyznaczony inicjator”?
3 odpowiedzi
Wyznaczony inicjator to ten, który muszą wywołać wszystkie inne inicjatory. UIView
i podklasy są nieco nietypowe, ponieważ mają dwa takie inicjatory: -initWithFrame:
i -initWithCoder:
, w zależności od tego, jak tworzony jest widok. Powinieneś nadpisać -initWithFrame:
, jeśli tworzysz instancję widoku w kodzie, i -initWithCoder:
, jeśli ładujesz go z końcówki. Lub możesz umieścić swój kod w trzeciej metodzie i nadpisać oba te inicjatory tak, aby wywołały trzecią metodę. W rzeczywistości jest to często zalecana strategia.
Na przykład możesz utworzyć podklasę UIView, ClueCharacter
, która ma własną metodę inicjalizacji: -initWithPerson:place:thing:
. Następnie tworzysz swój widok w ten sposób:
Obiekt-C:
ClueCharacter *mustard = [[ClueCharacter alloc] initWithPerson:@"Col. Mustard"
place:kInTheStudy
thing:kTheRope];
Szybki:
var mustard = ClueCharacter("Col. Mustard", place: kInTheStudy, thing: kTheRope)
W porządku, ale aby zainicjować część UIView obiektu, twoja metoda musi wywołać wyznaczony inicjator:
Obiekt-C:
-(id)initWithPerson:(NSString*)name place:(CluePlace)place thing:(ClueWeapon)thing
{
if ((self = [super initWithFrame:CGRectMake(0, 0, 150, 200)])) {
// your init stuff here
}
}
Szybki:
func init(name: String, place : CluePlace, thing : ClueWeapon)
{
if (self = super.init(CGRectMake(0, 0, 150, 200))) {
// your init stuff here
}
}
Jeśli chcesz wywołać inicjator swojej podklasy -init
, jest to w porządku, o ile wywołasz -initWithFrame:
w implementacji.
W UIView
wywołanie [super init]
jest dokładnie równe [super initWithFrame:CGRectZero]
UIView
z wyznaczonym inicjatorem - wywołanie super.init()
spowoduje błąd kompilacji Must call a designated initializer of the superclass 'UIView'
, podczas gdy wywołanie super.init(frame: .zero)
działa dobrze.
W klasie Objective-C z wieloma inicjatorami wyznaczony inicjator to ten, który wykonuje znaczącą pracę. Tak więc często masz klasę z kilkoma inicjatorami, powiedzmy:
- (id)initWithRect:(CGRect)someRect;
- (id)initWithRect:(CGRect)someRect setDefaultColour:(BOOL)setDefaultColour;
- (id)initWithRect:(CGRect)someRect setDefaultColour:(BOOL)setDefaultColour
linkTo:(id)someOtherObject;
W takim przypadku normalnie (ale nie zawsze) powiedziałbyś, że trzeci był wyznaczonym inicjatorem i zaimplementowałbyś pozostałe dwa jako np.
- (id)initWithRect:(CGRect)someRect
{
return [self initWithRect:someRect setDefaultColour:NO];
}
- (id)initWithRect:(CGRect)someRect setDefaultColour:(BOOL)setDefaultColour
{
return [self initWithRect:someRect setDefaultColour:setDefaultColour
linkTo:nil];
}
Jeśli klasa ma tylko jeden inicjator, to jest to wyznaczony inicjator.
W twoim przypadku, aby postępować zgodnie z najlepszymi praktykami, powinieneś wdrożyć initWithFrame:
, a także waniliowy init:
, który wywołuje initWithFrame:
z normalnymi wymiarami. Normalna konwencja jest taka, że możesz dodawać nowe odmiany init
w podklasach, ale nie powinieneś ich usuwać, i że zawsze wykonujesz rzeczywistą pracę inicjującą w wyznaczonym inicjatorze. Dzięki temu wszystkie metody inicjujące z klasy nadrzędnej, których nie dostarczysz nowych implementacji, nadal będą poprawnie współpracować z twoją podklasą.
Podobne pytania
Powiązane pytania
Nowe pytania
ios
iOS to mobilny system operacyjny działający na urządzeniach Apple iPhone, iPod touch i iPad. Użyj tego tagu [ios] w przypadku pytań związanych z programowaniem na platformie iOS. Użyj powiązanych tagów [objective-c] i [swift] w przypadku problemów specyficznych dla tych języków programowania.
[self initWithPerson:nil place:nil thing:nil]
). Ponadto wyznaczony inicjator nadklasy powinien zostać nadpisany, aby wywołać nowy wyznaczony inicjator.-initWithFrame:
lub-initWithCoder:
i żadne z nich nie wywołuje drugiego. Tak więc w przypadku widoków faktycznie istnieją dwa wyznaczone inicjatory. Zobacz także dokumentację dotyczącą-initWithFrame:
.