web-dev-qa-db-fra.com

Initialiseurs désignés iOS: utilisation de NS_DESIGNATED_INITIALIZER

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é.

34
Mehul Parmar

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: "")
    }
}
55
Martin R

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.

12
Timur Bernikovich

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 .

1
larva