228 votes

Serait-il avantageux de commencer à utiliser instancetype au lieu de l'id?

Clang ajoute un mot-clé instancetype que, aussi loin que je peux voir, remplace id un type de retour, en -alloc et init.

Est-il un avantage à l'utilisation d' instancetype au lieu de id?

339voto

Steven Fisher Points 22249

Oui, il y a des avantages à l'aide d' instancetype dans tous les cas où elle s'applique. Je vais vous expliquer plus en détail, mais permettez-moi de commencer avec cette déclaration audacieuse: Utiliser instancetype chaque fois que c'est nécessaire, ce qui est à chaque fois une classe renvoie une instance de la même classe.

En fait, voici ce que Apple dit maintenant sur le sujet:

Dans votre code, remplace les occurrences de id comme valeur de retour, avec instancetype le cas échéant. C'est généralement le cas pour init méthodes de classe et de méthodes de fabrique. Même si le compilateur convertit automatiquement les méthodes qui commencent par "alloc", de "init" ou "nouveau" et avoir un type de retour d' id de revenir instancetype, il ne convertit pas les autres méthodes. Objective-C de la convention est d'écrire instancetype explicitement pour toutes les méthodes.

Avec cela de la route, passons à autre chose et d'expliquer pourquoi c'est une bonne idée.

Tout d'abord, quelques définitions:

 @interface Foo:NSObject
 - (id)initWithBar:(NSInteger)bar; // initializer
 + (id)fooWithBar:(NSInteger)bar;  // class factory
 @end

Pour une fabrique de classe, vous devez toujours utiliser instancetype. Le compilateur ne convertit pas automatiquement id de instancetype. Qu' id est un objet générique. Mais si vous faites un instancetype le compilateur sait quel type d'objet, la méthode retourne.

Ce n'est pas un universitaire problème. Par exemple, [[NSFileHandle fileHandleWithStandardOutput] writeData:formattedData] va générer une erreur sur Mac OS X (seulement) Plusieurs méthodes nommé "writeData:" trouvés avec dépareillés conséquent, le type de paramètre ou les attributs. La raison en est que les deux NSFileHandle et NSURLHandle fournir un writeData:. Depuis [NSFileHandle fileHandleWithStandardOutput] renvoie un id, le compilateur n'est pas certain de ce que la classe writeData: a appelée.

Vous avez besoin de travailler autour de cela, en utilisant soit:

[(NSFileHandle *)[NSFileHandle fileHandleWithStandardOutput] writeData:formattedData];

ou:

NSFileHandle *fileHandle = [NSFileHandle fileHandleWithStandardOutput];
[fileHandle writeData:formattedData];

Bien sûr, la meilleure solution est de déclarer fileHandleWithStandardOutput comme retournant un instancetype. Ensuite, la distribution ou à la cession n'est pas nécessaire.

(À noter que sur iOS, cet exemple ne produira pas une erreur que seulement NSFileHandle fournit un writeData: . D'autres exemples existent, comme length, ce qui renvoie une CGFloat de UILayoutSupport mais NSUInteger de NSString.)

Pour les initialiseurs, c'est plus compliqué. Lorsque vous tapez ceci:

- (id)initWithBar:(NSInteger)bar

...le compilateur fera semblant que vous avez tapé ceci à la place:

- (instancetype)initWithBar:(NSInteger)bar

Cela était nécessaire pour l'ARC. Ceci est décrit dans Clang Extensions de Langage Liés à des types de résultats. C'est pourquoi les gens vous diront qu'il n'est pas nécessaire d'utiliser instancetype, mais je pense que vous devriez. Le reste de cette réponse traite de cette.

Il y a trois avantages:

  1. Explicite. Votre code est en train de faire ce qu'il dit, plutôt que quelque chose d'autre.
  2. De modèle. Vous êtes en train de construire de bonnes habitudes pour une fois il n'est question, qui n'existe pas.
  3. La cohérence. Vous avez établi une certaine cohérence dans votre code, ce qui le rend plus lisible.

Explicite

C'est vrai qu'il n'y a pas de technique bénéficier de revenir instancetype d'un init. Mais c'est parce que le compilateur convertit automatiquement l' id de instancetype. Vous êtes en s'appuyant sur cette bizarrerie; lorsque vous écrivez que l' init renvoie un id, le compilateur est l'interprétant comme si elle renvoie un instancetype.

Ce sont l'équivalent pour le compilateur:

- (id)initWithBar:(NSInteger)bar;
- (instancetype)initWithBar:(NSInteger)bar;

Ce ne sont pas équivalent à vos yeux. Au mieux, vous apprendrez à ignorer la différence et de l'effleurer. Ce n'est pas quelque chose que vous devriez apprendre à ignorer.

Modèle

Alors il n'y a pas de différence avec init et d'autres méthodes, il y est une différence dès que vous définissez une classe d'usine.

Ces deux ne sont pas équivalents:

+ (id)fooWithBar:(NSInteger)bar;
+ (instancetype)fooWithBar:(NSInteger)bar;

Vous voulez la deuxième forme. Si vous avez l'habitude de taper instancetype que le type de retour d'un constructeur, vous aurez droit à chaque fois.

La cohérence

Enfin, imaginez si vous mettez tout cela ensemble: vous voulez un init de la fonction et aussi une fabrique de classe.

Si vous utilisez id pour init, vous vous retrouvez avec un code comme ceci:

- (id)initWithBar:(NSInteger)bar;
+ (instancetype)fooWithBar:(NSInteger)bar;

Mais si vous utilisez instancetype, vous obtenez ceci:

- (instancetype)initWithBar:(NSInteger)bar;
+ (instancetype)fooWithBar:(NSInteger)bar;

C'est plus cohérent et plus lisible. Ils renvoient la même chose, et maintenant, c'est évident.

Conclusion

Sauf si vous êtes intentionnellement à l'écriture de code pour les anciens compilateurs, vous devez utiliser instancetype le cas échéant.

Vous devriez hésité avant d'écrire un message qui renvoie id. Demandez-vous: Est-ce le retour d'une instance de cette classe? Si oui, c'est un instancetype.

Il y a certainement des cas où vous avez besoin de revenir id, mais vous aurez probablement utiliser instancetype beaucoup plus fréquemment.

197voto

Catfish_Man Points 15439

Il ya certainement un avantage. Lorsque vous utilisez 'id', vous obtenez essentiellement aucune vérification de type. Avec type d'instance, le compilateur et l'IDE de savoir ce genre de chose est retourné, et peut vérifier votre code de la meilleure et la saisie semi-automatique de mieux.

Utiliser uniquement dans un endroit où il fait sens, bien sûr (c'est à dire une méthode qui retourne une instance de cette classe); id est toujours utile.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X