Ich habe eine Unterklasse von UIView
erstellt, die einen festen Rahmen hat. Kann ich also einfach init
anstelle von initWithFrame:
Überschreiben? Z.B.:
- (id)init {
if ((self = [super initWithFrame:[[UIScreen mainScreen] bounds]])) {
self.backgroundColor = [UIColor clearColor];
}
return self;
}
In der Xcode-Dokumentation für -initWithFrame:
Heißt es: "Wenn Sie ein Ansichtsobjekt programmgesteuert erstellen, ist diese Methode der festgelegte Initialisierer für die Klasse UIView
. Unterklassen können diese Methode überschreiben, um eine benutzerdefinierte Initialisierung durchzuführen, müssen sie jedoch aufrufen super
zu Beginn ihrer Implementierung. "
Was bedeutet "Designated Initializer"?
Der angegebene Initialisierer ist derjenige, den alle anderen Initialisierer aufrufen müssen. UIView
und Unterklassen sind insofern etwas ungewöhnlich, als sie tatsächlich zwei solche Initialisierer haben: -initWithFrame:
und -initWithCoder:
, je nachdem, wie die Ansicht erstellt wird. Sie sollten -initWithFrame:
Überschreiben, wenn Sie die Ansicht im Code instanziieren, und -initWithCoder:
, Wenn Sie sie von einer Schreibfeder laden. Oder Sie können Ihren Code in die dritte Methode einfügen und beide Initialisierer so überschreiben, dass sie Ihre dritte Methode aufrufen. In der Tat ist das oft die empfohlene Strategie.
So können Sie beispielsweise eine UIView-Unterklasse, ClueCharacter
, mit einer eigenen Initialisierungsmethode erstellen: -initWithPerson:place:thing:
. Sie erstellen dann Ihre Ansicht wie folgt:
Objekt-C:
ClueCharacter *mustard = [[ClueCharacter alloc] initWithPerson:@"Col. Mustard"
place:kInTheStudy
thing:kTheRope];
Schnell:
var mustard = ClueCharacter("Col. Mustard", place: kInTheStudy, thing: kTheRope)
Das ist in Ordnung, aber um den UIView-Teil des Objekts zu initialisieren, muss Ihre Methode must den angegebenen Initialisierer aufrufen:
Objekt-C:
-(id)initWithPerson:(NSString*)name place:(CluePlace)place thing:(ClueWeapon)thing
{
if ((self = [super initWithFrame:CGRectMake(0, 0, 150, 200)])) {
// your init stuff here
}
}
Schnell:
func init(name: String, place : CluePlace, thing : ClueWeapon)
{
if (self = super.init(CGRectMake(0, 0, 150, 200))) {
// your init stuff here
}
}
Wenn Sie den Initialisierer Ihrer Unterklasse -init
Aufrufen möchten, ist dies in Ordnung, solange Sie in der Implementierung -initWithFrame:
Aufrufen.
in UIView
aufruf [super init]
ist genau gleich [super initWithFrame:CGRectZero]
In einer Objective-C-Klasse mit mehreren Initialisierern ist der angegebene Initialisierer derjenige, der die sinnvolle Arbeit leistet. So haben Sie oft eine Klasse mit ein paar Initialisierern, sagen Sie:
- (id)initWithRect:(CGRect)someRect;
- (id)initWithRect:(CGRect)someRect setDefaultColour:(BOOL)setDefaultColour;
- (id)initWithRect:(CGRect)someRect setDefaultColour:(BOOL)setDefaultColour
linkTo:(id)someOtherObject;
In diesem Fall würden Sie normalerweise (aber nicht immer) sagen, dass der dritte der festgelegte Initialisierer war, und die anderen beiden als z.
- (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];
}
Wenn eine Klasse nur einen Initialisierer hat, ist dies der festgelegte Initialisierer.
Um die Best Practice zu befolgen, sollten Sie initWithFrame:
und auch eine Vanille init:
das ruft initWithFrame:
mit Ihren normalen Maßen. Die übliche Konvention ist, dass Sie neue Variationen von init
in Unterklassen hinzufügen können, diese aber nicht wegnehmen sollten und dass Sie die eigentliche Initialisierungsarbeit immer im festgelegten Initialisierer ausführen. Auf diese Weise können alle Initialisierungsmethoden der übergeordneten Klasse, für die Sie keine neuen Implementierungen bereitstellen, mit Ihrer Unterklasse ordnungsgemäß zusammenarbeiten.