2014-01-18 8 views
5

Kann jemand erklären, warum wir if (self == SomeClass class) innerhalb der +initialize Methode einschließen müssen?Implementierung von -init vs. + initialize

ich gefunden habe ähnliche Fragen (siehe unten), aber finden keine spezifischen Abklärungen:

  1. Objective-C: init vs initialize
  2. Should +initialize/+load always start with an: if (self == [MyClass class]) guard?

Jeder sagt, dass, wenn Sie nicht implementieren/override +initialize in Subclass, dann wird es die Elternklasse zweimal aufrufen.

Kann jemand diesen Teil insbesondere erklären, warum nennt er die Elternklasse zweimal?

Schließlich, warum passiert es nicht, wenn wir +initialize in der Klasse implementieren, die von NSObject erbt, wo wir eine benutzerdefinierte -init Methode erstellen und self = [super init]; aufrufen.

+0

init und initialisieren haben nichts miteinander zu tun. – rmaddy

+0

@rmaddy Innerhalb von '-init' hast du' self = [super init]; 'was die Eltern' 'initialize' 'aufruft, oder bin ich nicht korrekt? – makaed

+1

Sie sind nicht korrekt. initialize wird einmal pro Klasse aufgerufen, bevor eine andere Klassen- oder Instanzmethode aufgerufen wird. – rmaddy

Antwort

4

-init und +initialize sind ganz andere Dinge. Die erste ist für die Initialisierung Instanzen; Die zweite ist für die Initialisierung Klassen.

Wenn eine Klasse zum ersten Mal eine Nachricht erhält, stellt die Laufzeitumgebung sicher, dass +initialize darauf und ihre Oberklassen aufgerufen wird. Die Oberklassen werden zuerst initialisiert, da sie bereit sein müssen, bevor sich irgendeine Unterklasse initialisieren kann.

So, die ersten, die Zeit YourSubclass messaged ist, kann die Laufzeit wie etwas tun:

[NSObject initialize]; 
[YourClass initialize]; 
[YourSubclass initialize]; 

(Obwohl es sehr unwahrscheinlich ist, dass dies das erste Mal sein würde, dass NSObject messaged ist, so wahrscheinlich es doesn‘ t müssen an diesem Punkt initialisiert werden. Es ist nur zur Veranschaulichung.)

Wenn YourSubclass nicht +initialize nicht implementiert, wird der [YourSubclass initialize] Aufruf oben gezeigt wird +[YourClass initialize] tatsächlich nennen. Das ist nur der normale Vererbungsmechanismus bei der Arbeit. Das wird das zweite Mal, dass +[YourClass initialize] aufgerufen wurde.

Da die Arbeit in einer +initialize-Methode in der Regel die Art von Sache ist, die nur einmal durchgeführt werden sollte, ist der Schutz if (self == [TheClassWhoseImplementationThisMethodIsPartOf class]) erforderlich. Außerdem geht diese Arbeit oft davon aus, dass sich self auf die aktuelle geschriebene Klasse bezieht, also auch ein Grund für den Wächter.

Die zweite Antwort zitiert eine Ausnahme, die der alte Stil Mechanismus zum Registrieren KVO-abhängige Schlüssel mit der +setKeys:triggerChangeNotificationsForDependentKey: Methode ist. Diese Methode ist spezifisch für die tatsächliche Klasse, für die sie aufgerufen wird, und nicht für Unterklassen. Sie sollten es vermeiden und die moderneren Methoden +keyPathsForValuesAffectingValueForKey: oder +keyPathsForValuesAffecting<Key> verwenden. Wenn Sie den alten Weg benutzen müssen, legen Sie diesen Teil außerhalb des Schutzes. Außerdem müssen Unterklassen einer solchen Klasse bis super durchgehen, was normalerweise nicht erfolgt.

Update:

Ein +initialize Verfahren soll in der Regel nicht durch super nennen, weil die Laufzeit bereits die übergeordnete Klasse initialisiert wird. Wenn und nur wenn die Oberklasse bekannt ist, abhängige Schlüssel unter Verwendung des alten Mechanismus zu registrieren, dann müssen alle Unterklassen zu super aufrufen.

Die gleiche Sorge existiert nicht im Fall von -init, weil die Laufzeit nicht automatisch die Superklassen-Init-Methode für Sie aufruft, bevor Sie Ihre aufruft. Wenn Ihre Init-Methode nicht zu super aufruft, dann hat nichts den "Teil" der Instanz der Superklasse initialisiert.

+0

Wäre "TheClassWhoseImplementationThisMethodIsPartOf" in Ihrem Beispiel "YourClass"? – makaed

+1

Innerhalb der Implementierung von '+ [YourClass initialize]', ja. Ich habe versucht, es allgemein zu machen. –

0

Die von Ihnen zitierten Fragen haben gute, akzeptierte Antworten. Zusammenfassend wird +initialize von der Laufzeit für jede Klasse aufgerufen, also für eine Oberklasse mit N Unterklassen wird sie N + 1 Mal in der Oberklasse aufgerufen (einmal direkt und einmal für jede Unterklasse, die sie erbt). Dasselbe gilt, wenn eine Unterklasse sie überschreibt und super aufruft.

Sie können sich dagegen wehren, indem Sie auf der Oberklassenebene fragen: "Ist das meine direkte Initialisierung durch das System und nicht 'Super', das von meiner Unterklasse vererbt oder aufgerufen wird?"

if (self == [ThisSuperclass self]) {} 

-init verwendeten Instanzen von Klassen zu initialisieren und wird nicht durch die Laufzeit standardmäßig wie +initialize aufgerufen. Instanzen erben ihre Implementierungen von -init, können die geerbte Implementierung außer Kraft setzen und können außerdem den Vorteil der geerbten Implementierung durch Aufruf von [super init]; nutzen.

+0

Also wird '+ initialize' auf jeden Fall von der Laufzeit aufgerufen, ohne Code vom Benutzer? Wenn ja, frage ich mich, in welchem ​​Fall dann "+ initialisiere" auf super in der Unterklasse genannt werden würde? – makaed

+1

@danh, es ist nicht nur, wenn die Unterklasse "Super" aufruft, dass die Methode zweimal aufgerufen wird. Dies ist auch der Fall, wenn die Unterklasse nicht '+ initialize' implementiert, was bei weitem die häufigste Situation ist. –

+0

Ich verstehe. Danke, ich habe es bearbeitet. – danh

5

Stellen Sie sich vor, Sie haben eine Superklasse, die +initialize implementiert und eine Unterklasse, die nicht funktioniert.

@interface SuperClass : NSObject @end 
@implementation SuperClass 
+(void)initialize { 
    NSLog(@"This is class %@ running SuperClass +initialize", self); 
} 
@end 

@interface SubClass : SuperClass @end 
@implementation SubClass 
// no +initialize implementation 
@end 

Verwenden Sie die Oberklasse. Dies provoziert einen Anruf an +[SuperClass initialize].

[SuperClass class]; 
=> This is class SuperClass running SuperClass +initialize 

Verwenden Sie jetzt die Unterklasse. Die Laufzeit sucht nach einer Implementierung von +initialize in SubClass und findet nichts. Dann sucht es nach einer geerbten Implementierung in SuperClass und findet es. Die geerbte Implementierung wird auch genannt, obwohl es schon einmal im Namen von SuperClass selbst genannt wurde:

[SubClass class]; 
=> This is class SubClass running SuperClass +initialize 

Der Wächter ermöglicht es Ihnen, Arbeit zu verrichten, die höchstens einmal ausgeführt werden muß. Alle nachfolgenden Aufrufe an +initialize haben eine andere Klasse als self, so dass der Wächter sie ignorieren kann.

Verwandte Themen