Objective-C: diferencia entre id y void *

¿Cuál es la diferencia entre id y void * ?

void * significa “una referencia a algún trozo aleatorio de memoria con contenido sin tipo / desconocido”

id significa “una referencia a algún objeto aleatorio Objective-C de clase desconocida”

Hay diferencias semánticas adicionales:

  • En los modos GC Only o GC Supported, el comstackdor emitirá barreras de escritura para las referencias de tipo id , pero no para el tipo void * . Al declarar estructuras, esto puede ser una diferencia crítica. Declarando iVars como void *_superPrivateDoNotTouch; causará cosecha prematura de objetos si _superPrivateDoNotTouch es realmente un objeto. No hagas eso.

  • intentar invocar un método en una referencia de tipo void * eliminará una advertencia del comstackdor.

  • intentar invocar un método en un tipo de id . solo advertirá si el método que se está llamando no ha sido declarado en ninguna de las declaraciones de @interface vistas por el comstackdor.

Por lo tanto, uno nunca debe referirse a un objeto como un void * . Del mismo modo, uno debe evitar el uso de una variable de tipo id para referirse a un objeto. Use la referencia de tipo de clase más específica que pueda. Incluso NSObject * es mejor que id porque el comstackdor puede, como mínimo, proporcionar una mejor validación de las invocaciones de métodos con respecto a esa referencia.

El único uso común y válido de void * es como una referencia de datos opacos que se pasa a través de otra API.

Considere el sortedArrayUsingFunction: context: de NSArray :

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

La función de clasificación se declararía como:

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

En este caso, el NSArray simplemente transfiere todo lo que pasa como argumento de context al método a través del argumento de context . Es un trozo opaco de datos del tamaño de un puntero, en lo que respecta a NSArray, y usted es libre de usarlo para el propósito que desee.

Sin una característica de tipo de cierre en el idioma, esta es la única manera de llevar consigo una gran cantidad de datos con una función. Ejemplo; si quisiera que mySortFunc () clasificara condicionalmente como sensible a mayúsculas y minúsculas o sin distinción entre mayúsculas y minúsculas, y al mismo tiempo fuera de subprocesos, pasaría el indicador de mayúsculas y minúsculas en el contexto, probablemente en el modo de entrada y salida.

Frágil y propenso a errores, pero la única forma.

Los bloques resuelven esto: los bloques son cierres para C. Están disponibles en Clang – http://llvm.org/ y están presentes en Snow Leopard ( http://developer.apple.com/library/ios/documentation/Performance /Reference/GCD_libdispatch_Ref/GCD_libdispatch_Ref.pdf ).

id es un puntero a un objeto objective C, donde como void * es un puntero a cualquier cosa.

id también desactiva las advertencias relacionadas con llamar a métodos desconocidos, por ejemplo:

[(id)obj doSomethingWeirdYouveNeverHeardOf];

no dará la advertencia habitual sobre métodos desconocidos. Obtendrá, por supuesto, una excepción en tiempo de ejecución a menos que obj sea nulo o realmente implemente ese método.

A menudo debes usar NSObject* o id con preferencia a id , lo que al menos confirma que el objeto devuelto es un objeto Cocoa, por lo que puedes usar métodos como retener / liberar / liberar automáticamente.

Si un método tiene un tipo de devolución de id , puede devolver cualquier objeto Objective-C.

void significa que el método no devolverá nada.

void * es solo un puntero. No podrá editar el contenido en la dirección a la que apunta el puntero.

id es un puntero a un objeto Objective-C. void * es un puntero a cualquier cosa . Puede usar void * lugar de id , pero no se recomienda porque nunca obtendrá advertencias de comstackción para nada.

Es posible que desee ver stackoverflow.com/questions/466777/whats-the-difference-between-declaring-a-variable-id-and-nsobject y 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; 

El código anterior es de objc.h, por lo que parece que id es una instancia de objc_object struct y es un puntero que puede vincularse con cualquier objeto de la clase Objective C, mientras que void * es solo un puntero sin tipo.

Mi entendimiento es que id representa un puntero a un objeto mientras que void * puede apuntar a algo realmente, siempre y cuando lo moldees al tipo que quieras usar como

Además de lo que ya se dijo, hay una diferencia entre los objetos y los indicadores relacionados con las colecciones. Por ejemplo, si quiere poner algo en NSArray, necesita un objeto (de tipo “id”) y no puede usar un puntero de datos sin procesar (de tipo “void *”). Puede usar [NSValue valueWithPointer:rawData] para convertir void *rawDdata en el tipo “id” para usarlo dentro de una colección. En general, “id” es más flexible y tiene más semántica relacionada con los objetos adjuntos. Hay más ejemplos que explican el tipo de Id. Del Objetivo C aquí .