Nous avons cette nouvelle macro introduite dans XCode 6: NS_DESIGNATED_INITIALIZER
J'ai cherché sur le net, mais je n'ai pas vraiment trouvé de bonne documentation sur la façon de l'utiliser.
Syntaxiquement, nous pouvons l'utiliser comme:
- (instancetype)initWithCoder:(NSCoder *)coder NS_DESIGNATED_INITIALIZER;
Mais quels sont les avantages possibles de marquer un initialiseur avec cette macro, et quelles sont les choses que nous devrions considérer lorsque nous utilisons cela?
Je m'intéresse principalement aux cas d'utilisation de cette macro. Tout lien/documentation serait apprécié.
L'utilisation de NS_DESIGNATED_INITIALIZER
est bien expliqué dans http://useyourloaf.com/blog/2014/08/19/xcode-6-objective-c-modernization.html :
L'initialiseur désigné garantit que l'objet est complètement initialisé en envoyant un message d'initialisation à la superclasse. Le détail de l'implémentation devient important pour un utilisateur de la classe lorsqu'il la sous-classe. Les règles pour les initialiseurs désignés en détail:
- Un initialiseur désigné doit appeler (via super) un initialiseur désigné de la superclasse. Lorsque NSObject est la superclasse, c'est juste [super init].
- Tout initialiseur de commodité doit appeler un autre initialiseur de la classe - ce qui conduit finalement à un initialiseur désigné.
- Une classe avec des initialiseurs désignés doit implémenter tous les initialiseurs désignés de la superclasse.
Par exemple, si votre interface est
@interface MyClass : NSObject
@property(copy, nonatomic) NSString *name;
-(instancetype)initWithName:(NSString *)name NS_DESIGNATED_INITIALIZER;
-(instancetype)init;
@end
alors le compilateur vérifie si l'initialiseur (de commodité) init
appelle l'initialiseur (désigné) initWithName:
, cela entraînerait donc un avertissement:
-(instancetype)init
{
self = [super init];
return self;
}
et ce serait OK:
-(instancetype)init
{
self = [self initWithName:@""];
return self;
}
Dans Swift les règles concernant les initialiseurs désignés et de commodité sont encore plus strictes, et si vous mélangez Objective-C et Swift , le marquage des initialiseurs Objective-C désignés aide le compilateur à appliquer les règles.
Par exemple, cette sous-classe Swift entraînerait une erreur de compilation:
class SwClass: MyClass {
var foo : String
init(foo : String) {
self.foo = foo
super.init()
}
}
et ce serait OK:
class SwClass: MyClass {
var foo : String
init(foo : String) {
self.foo = foo
super.init(name: "")
}
}
Ma façon la plus courante de le faire:
@interface Person : NSObject
- (nullable instancetype)initWithName:(nonnull NSString *)name NS_DESIGNATED_INITIALIZER;
- (nullable instancetype)init NS_UNAVAILABLE;
@property (nonatomic, nonnull) NSString *name;
@end
Et mise en œuvre
@implementation Person
- (instancetype)initWithName:(NSString *)name
{
self = [super init];
if (self) {
self.name = name;
}
return self;
}
@end
Dans ce cas, vous ne devez pas remplacer NS_DESIGNATED_INITIALIZER
de votre méthode de superclasse (NSObject
's init:
dans ce cas) - nous avons utilisé NS_UNAVAILABLE
pour marquer cette méthode comme inutile. Ou vous pouvez le remplacer pour appeler votre initialiseur désigné avec des paramètres par défaut.
Les initialiseurs désignés définissent la façon dont nous structurons nos initialiseurs lors du sous-classement; ils sont l '"initialiseur canonique" de votre classe. Il est garanti fiable quel que soit l'initialiseur désigné dans la chaîne de superclasse que vous appelez, et ira toujours de l'ancêtre le plus éloigné au plus descendant le plus éloigné.
Un initialiseur désigné ne définit pas quel initialiseur vous devez utiliser lors de la création d'un objet. C'est très expliqué dans https://blog.Twitter.com/2014/how-to-objective-c-initializer-patterns .