2014-10-03 1 views
27

Wir haben das neue Makro in XCode werden 6 eingeführt: NS_DESIGNATED_INITIALIZERiOS Designated Initializers: Mit NS_DESIGNATED_INITIALIZER

ich im Netz gesucht, konnte aber nicht wirklich eine gute Dokumentation, wie diese zu verwenden.

syntaktisch, können wir es gerne verwenden:

- (instancetype)initWithCoder:(NSCoder *)coder NS_DESIGNATED_INITIALIZER; 

Aber was sind die möglichen Vorteile eines initializer mit diesem Makro-Kennzeichnung, und auch, was sind die Dinge, die wir suchen sollte, wenn diese mit?

Ich interessiere mich hauptsächlich für die Anwendungsfälle dieses Makros. Irgendwelche Verbindungen/Dokumentationen würden geschätzt.

Antwort

44

Die Verwendung von NS_DESIGNATED_INITIALIZER schön in http://useyourloaf.com/blog/2014/08/19/xcode-6-objective-c-modernization.html erklärt:

The designated initializer guarantees the object is fully initialised by sending an initialization message to the superclass. The implementation detail becomes important to a user of the class when they subclass it. The rules for designated initializers in detail:

  • A designated initializer must call (via super) a designated initializer of the superclass. Where NSObject is the superclass this is just [super init].
  • Any convenience initializer must call another initializer in the class - which eventually leads to a designated initializer.
  • A class with designated initializers must implement all of the designated initializers of the superclass.

Als Beispiel, wenn Ihre Schnittstelle ist

@interface MyClass : NSObject 
@property(copy, nonatomic) NSString *name; 
-(instancetype)initWithName:(NSString *)name NS_DESIGNATED_INITIALIZER; 
-(instancetype)init; 
@end 

dann der Compiler prüft, ob die (Bequemlichkeit) initializer init ruft die (bezeichnet) Initialisierer initWithName:, so würde dies eine Warnung verursachen:

-(instancetype)init 
{ 
    self = [super init]; 
    return self; 
} 

und das wäre in Ordnung sein:

-(instancetype)init 
{ 
    self = [self initWithName:@""]; 
    return self; 
} 

In Swift die Regeln über bezeichnet und Bequemlichkeit initializers sind noch strenger, und wenn Sie Objective-C und Swift Code mischen, Kennzeichnung der benannten Ziel -C-Initialisierer helfen dem Compiler, die Regeln zu erzwingen.

Zum Beispiel dieser Swift Unterklasse würde einen Compiler-Fehler verursachen:

class SwClass: MyClass { 
    var foo : String 
    init(foo : String) { 
     self.foo = foo 
     super.init() 
    } 
} 

und das wäre in Ordnung sein:

class SwClass: MyClass { 
    var foo : String 
    init(foo : String) { 
     self.foo = foo 
     super.init(name: "") 
    } 
} 
+2

Es ist nicht sehr gut durch Konzept gedacht, in Objective-C, weil 'initWithName: @„“' nicht immer sinnvoll ist, wenn Subklassifizieren. Statt normalerweise außer Kraft gesetzt bestimmte Initialisierung von Super wirft Ausnahme sollte verwenden bestimmte Initialisierung von Unterklasse zu sagen. – Andy

+5

Martins Antwort hinzuzufügen, Sie möchten die Benutzer rufen die Standard initialisers vollständig zu unterdrücken, in dem Fall, dass Sie die folgende verwenden: - (instanceType) NS_UNAVAILABLE init; –

1

Designated initializers definieren, wie wir unsere initializers strukturieren, wenn Subklassen; Sie sind der "kanonische Initialisierer" für Ihre Klasse. Es ist garantiert zuverlässig, unabhängig davon, welcher Initialisierer in der Superklassen-Kette, die Sie aufrufen, ist und wird immer vom weitesten Vorfahren zum am weitesten entfernten Nachkommen gehen.

Ein designierter Initializer definiert nicht, welchen Initialisierer Sie beim Erstellen eines Objekts verwenden sollten. Es ist sehr in https://blog.twitter.com/2014/how-to-objective-c-initializer-patterns erklärt.

6

Mein gängigste Weg, dies zu tun:

@interface Person : NSObject 

- (nullable instancetype)initWithName:(nonnull NSString *)name NS_DESIGNATED_INITIALIZER; 
- (nullable instancetype)init NS_UNAVAILABLE; 

@property (nonatomic, nonnull) NSString *name; 

@end 

und Umsetzung

@implementation Person 

- (instancetype)initWithName:(NSString *)name 
{ 
    self = [super init]; 
    if (self) { 
     self.name = name; 
    } 
    return self; 
} 

@end 

In diesem Fall außer Kraft setzen Sie sollen nicht NS_DESIGNATED_INITIALIZER Ihre Oberklassenmethode (NSObject ‚s init: in diesem Fall) - Wir haben NS_UNAVAILABLE verwendet, um diese Methode als nicht erforderlich zu markieren.Oder Sie können außer Kraft setzen sie Ihre bestimmte Initialisierung mit Standardparametern zu nennen.