Quelle est la différence entre id
et void *
?
Réponses
Trop de publicités?void *
signifie "une référence à une partie aléatoire de la mémoire avec un contenu inconnu".
id
signifie "une référence à un objet Objective-C aléatoire de classe inconnue".
Il existe des différences sémantiques supplémentaires :
-
Dans les modes GC Only ou GC Supported, le compilateur émettra des barrières d'écriture pour les références de type
id
mais pas pour le typevoid *
. Lors de la déclaration de structures, cette différence peut s'avérer cruciale. Déclarer des iVars commevoid *_superPrivateDoNotTouch;
entraînera une récolte prématurée d'objets si_superPrivateDoNotTouch
est en fait un objet. Ne faites pas ça. -
en essayant d'invoquer une méthode sur une référence de
void *
fera apparaître un avertissement du compilateur. -
en tentant d'invoquer une méthode sur un
id
n'émettra un avertissement que si la méthode appelée n'a pas été déclarée dans l'une des catégories de l'annexe 1.@interface
déclarations vues par le compilateur.
Ainsi, il ne faut jamais faire référence à un objet en tant que void *
. De même, il faut éviter d'utiliser un id
variable typée pour faire référence à un objet. Utilisez la référence typée classe la plus spécifique possible. Même NSObject *
est meilleur que id
car le compilateur peut, au moins, fournir une meilleure validation des invocations de méthodes par rapport à cette référence.
La seule utilisation commune et valide de void *
est une référence de données opaque qui est transmise par une autre API.
Considérez le sortedArrayUsingFunction: context:
méthode de NSArray
:
- (NSArray *)sortedArrayUsingFunction:(NSInteger (*)(id, id, void *))comparator context:(void *)context;
La fonction de tri serait déclarée comme :
NSInteger mySortFunc(id left, id right, void *context) { ...; }
Dans ce cas, la NSArray se contente de transmettre ce que vous passez en tant que context
à la méthode par le biais de l'argument context
argument. Il s'agit d'un morceau opaque de données de la taille d'un pointeur, dans la mesure où NSArray est concerné, et vous êtes libre de l'utiliser dans le but que vous souhaitez.
En l'absence d'une fonctionnalité de type fermeture dans le langage, c'est le seul moyen de transporter un gros morceau de données avec une fonction. Exemple : si vous vouliez que mySortFunc() trie conditionnellement en fonction de la casse ou de l'insensibilité à la casse, tout en étant sûr pour les threads, vous passeriez l'indicateur is-case-sensitive dans le contexte, en effectuant probablement un casting à l'entrée et à la sortie.
Fragile et sujet aux erreurs, mais la seule solution.
Les blocs résolvent ce problème -- Les blocs sont des fermetures pour C. Ils sont disponibles dans Clang --. http://llvm.org/ et sont omniprésents dans Snow Leopard ( http://developer.apple.com/library/ios/documentation/Performance/Reference/GCD_libdispatch_Ref/GCD_libdispatch_Ref.pdf ).
Id est un pointeur vers un objet C objectif, alors que void* est un pointeur vers n'importe quoi.
id désactive également les avertissements liés à l'appel de méthodes inconnues, donc par exemple :
[(id)obj doSomethingWeirdYouveNeverHeardOf];
ne donnera pas l'avertissement habituel concernant les méthodes inconnues. Il lèvera, bien sûr, une exception au moment de l'exécution, à moins que obj ne soit nil ou qu'il implémente réellement cette méthode.
Vous devez souvent utiliser NSObject*
ou id<NSObject>
de préférence à id
ce qui confirme au moins que l'objet retourné est un objet Cocoa, et que vous pouvez donc utiliser en toute sécurité des méthodes comme retain/release/autorelease.
id
est un pointeur vers un objet Objective-C. void *
est un pointeur vers tout ce qui est . Vous pouvez utiliser void *
au lieu de id
mais ce n'est pas recommandé car vous n'obtiendrez jamais d'avertissements du compilateur pour quoi que ce soit.
Vous voudrez peut-être voir stackoverflow.com/questions/466777/whats-the-difference-between-declaring-a-variable-id-and-nsobject et unixjunkie.blogspot.com/2008/03/id-vs-nsobject-vs-id.html .