Objective-C: différence entre id et void *

Quelle est la différence entre id et void * ?

void * signifie “une référence à un morceau aléatoire de la mémoire avec un contenu non typé / inconnu”

id signifie “une référence à un object Objective-C aléatoire de classe inconnue”

Il y a des différences sémantiques supplémentaires:

  • En mode 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 type void * . Lorsque vous déclarez des structures, cela peut être une différence critique. Déclarer iVars comme void *_superPrivateDoNotTouch; causera une récolte prématurée des objects si _superPrivateDoNotTouch est en réalité un object. Ne fais pas ça.

  • tenter d’invoquer une méthode sur une référence de type void * affichera un avertissement du compilateur.

  • Si vous essayez d’invoquer une méthode sur un type d’ id , vous ne serez averti que si la méthode appelée n’a pas été déclarée dans les déclarations @interface vues par le compilateur.

Ainsi, on ne devrait jamais se référer à un object comme un void * . De même, il faut éviter d’utiliser une variable typée id pour faire référence à un object. Utilisez la référence typée de classe la plus spécifique que vous pouvez. Même NSObject * vaut mieux 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 courante et valide de void * est une référence de données opaque transmise via une autre API.

Considérez la sortedArrayUsingFunction: context: méthode de NSArray :

 - (NSArray *)sortedArrayUsingFunction:(NSInteger (*)(id, id, void *))comparator context:(void *)context; 

La fonction de sorting serait déclarée comme:

 NSInteger mySortFunc(id left, id right, void *context) { ...; } 

Dans ce cas, le NSArray transmet simplement ce que vous transmettez comme argument de context à la méthode via l’argument context . C’est un morceau opaque de données de taille de pointeur, en ce qui concerne NSArray, et vous êtes libre de l’utiliser pour n’importe quel but.

Sans une fonctionnalité de type de fermeture dans le langage, c’est le seul moyen de transporter un morceau de données avec une fonction. Exemple; Si vous vouliez que mySortFunc () soit classé comme sensible à la casse ou insensible à la casse, tout en étant toujours compatible avec les threads, vous passeriez l’indicateur sensible à la casse dans le contexte, probablement en cours de traitement.

Fragile et sujet aux erreurs, mais le seul moyen.

Les blocs résolvent ceci – 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 sur un object objective C, où void * est un pointeur sur n’importe quoi.

id désactive également les avertissements relatifs à l’appel de méthodes inconnues, par exemple:

[(id)obj doSomethingWeirdYouveNeverHeardOf];

ne donnera pas l’avertissement habituel sur les méthodes inconnues. Bien entendu, il générera une exception lors de l’exécution, à moins que obj soit nul ou implémente réellement cette méthode.

Vous devez souvent utiliser NSObject* ou id de préférence à id , ce qui confirme au moins que l’object renvoyé est un object Cocoa. Vous pouvez donc utiliser en toute sécurité des méthodes telles que keep / release / autorelease.

Si une méthode a un type de retour d’ id vous pouvez retourner n’importe quel object Objective-C.

void signifie que la méthode ne renverra rien.

void * est juste un pointeur. Vous ne pourrez pas modifier le contenu de l’adresse sur laquelle pointe le pointeur.

id est un pointeur vers un object Objective-C. void * est un pointeur vers n’importe quoi . Vous pouvez utiliser void * au lieu de id , mais ce n’est pas recommandé car vous ne recevrez jamais d’avertissement du compilateur pour quoi que ce soit.

Vous pouvez 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 .

 /// Represents an instance of a class. struct objc_object { Class isa OBJC_ISA_AVAILABILITY; }; /// A pointer to an instance of a class. typedef struct objc_object *id; 

Le code ci-dessus provient de objc.h, donc on dirait que id est une instance de la structure objc_object et isa un pointeur peut se lier avec n’importe quel object Objective C Class, alors que void * est juste un pointeur non typé.

D’après ce que je comprends, id représente un pointeur sur un object alors que void * peut indiquer quelque chose, à condition que vous le convertissiez au type que vous souhaitez utiliser.

En plus de ce qui a déjà été dit, il existe une différence entre les objects et les pointeurs liés aux collections. Par exemple, si vous voulez placer quelque chose dans NSArray, vous avez besoin d’un object (de type “id”) et vous ne pouvez pas utiliser un pointeur de données brutes (de type “void *”). Vous pouvez utiliser [NSValue valueWithPointer:rawData] pour convertir void *rawDdata au type “id” pour l’utiliser dans une collection. En général, “id” est plus flexible et a plus de sémantique liée aux objects qui lui sont attachés. Il y a plus d’exemples expliquant le type d’ID d’objective C ici .