wake-up-neo.com

iOS: UIView-Unterklasse init oder initWithFrame :?

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"?

37
ma11hew28

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.

73
Caleb

in UIView aufruf [super init] ist genau gleich [super initWithFrame:CGRectZero]

23
user1411443

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.

3
Tommy