Quelle est la difference entre id
et void *
?
void *
signifie "une référence à une partie aléatoire de la mémoire avec un contenu inconnu ou non typé"
id
signifie "une référence à un objet aléatoire Objective-C de classe inconnue"
Il existe d'autres différences sémantiques:
Sous les modes GC uniquement ou GC pris en charge, le compilateur émettra des barrières en écriture pour les références de type id
, mais pas pour le type void *
. Lors de la déclaration de structures, cela peut être une différence critique. Déclarer iVars comme void *_superPrivateDoNotTouch;
entraînera une récolte prématurée d'objets si _superPrivateDoNotTouch
est en fait un objet. Ne fais pas ça.
tenter d'invoquer une méthode sur une référence de void *
type va déclencher un avertissement du compilateur.
tenter d’invoquer une méthode sur un type id
avertira uniquement si la méthode appelée n’a été déclarée dans aucun des @interface
déclarations déclarées par le compilateur.
Ainsi, il ne faut jamais faire référence à un objet en tant que void *
. De même, il convient d'éviter d'utiliser une variable typée id
pour faire référence à un objet. Utilisez la référence typée de classe la plus spécifique possible. Même NSObject *
est meilleur que id
car le compilateur peut au moins mieux valider les invocations de méthodes par rapport à cette référence.
Le seul usage commun et valable de void *
est une référence de données opaque transmise via une autre API.
Prendre en compte 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, NSArray transmet simplement ce que vous transmettez sous forme d'argument context
à la méthode, sous forme d'argument context
. En ce qui concerne NSArray, il s’agit d’un bloc opaque de données de la taille d’un pointeur, et vous êtes libre de les utiliser à votre guise.
Sans une caractéristique de type fermeture dans le langage, c'est le seul moyen de transporter un bloc de données avec une fonction. Exemple; Si vous souhaitez que mySortFunc () effectue un tri conditionnel en fonction de la casse ou de la casse, tout en respectant les threads, vous passez l'indicateur sensible à la casse dans le contexte, ce qui risque de provoquer des entrées et des sorties.
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 objet Objective C, où void * est un pointeur sur n'importe quoi.
id désactive également les avertissements liés à 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 lève une exception lors de l'exécution, à moins que obj ne soit nul ou ne mette réellement en œuvre cette méthode.
Vous devez souvent utiliser NSObject*
ou id<NSObject>
de préférence à id
, qui confirme au moins que l’objet retourné est un objet Cocoa. Vous pouvez donc utiliser en toute sécurité des méthodes comme Retenir/Libérer/Autorelease.
Si une méthode a un type de retour de id
, vous pouvez renvoyer n'importe quel objet Objective-C.
void
signifie que la méthode ne renverra rien.
void *
n'est qu'un pointeur. Vous ne pourrez pas modifier le contenu de l'adresse indiquée par le pointeur.
id
est un pointeur sur un objet Objective-C. void *
est un pointeur sur n'importe quoi . Vous pouvez utiliser void *
au lieu de id
, mais ce n’est pas recommandé car vous n’auriez jamais les avertissements du compilateur.
Vous voudrez peut-être voir stackoverflow.com/questions/466777/whats-the-difference-between-declaring-a-variable-id-and-nsobject et nixjunkie.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 qu'un pointeur peut être lié à tout objet de la classe Objective C Class, tandis que void * n'est qu'un pointeur non typé.
D'après ce que je comprends, id représente un pointeur sur un objet, tandis que void * peut pointer vers n'importe quoi, tant que vous le définissez dans le type que vous souhaitez utiliser.
Outre ce qui a déjà été dit, il existe une différence entre les objets et les pointeurs liés aux collections. Par exemple, si vous souhaitez placer quelque chose dans NSArray, vous avez besoin d'un objet (de type "id") et vous ne pouvez pas utiliser de pointeur de données brutes (de type "void *"). Vous pouvez utiliser [NSValue valueWithPointer:rawData]
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 objets qui y sont attachés. Il y a plus d'exemples expliquant id type de Objective C ici .