Objective-C: differenza tra id e void *

Qual è la differenza tra id e void * ?

void * significa “riferimento ad un po ‘di memoria casuale con contenuti non tipizzati / sconosciuti”

id significa “riferimento ad un object Objective-C casuale di class sconosciuta”

Ci sono altre differenze semantiche:

  • Sotto GC Only o GC Supported mode, il compilatore emetterà barriere di scrittura per i riferimenti di tipo id , ma non per type void * . Quando si dichiarano le strutture, questa può essere una differenza fondamentale. Dichiarare iVars come void *_superPrivateDoNotTouch; causerà la raccolta anticipata di oggetti se _superPrivateDoNotTouch è in realtà un object. Non farlo.

  • il tentativo di invocare un metodo su un riferimento di tipo void * solleverà un avviso del compilatore.

  • il tentativo di invocare un metodo su un tipo di id avverte solo se il metodo chiamato non è stato dichiarato in nessuna delle dichiarazioni @interface viste dal compilatore.

Pertanto, non si dovrebbe mai fare riferimento a un object come void * . Allo stesso modo, si dovrebbe evitare di usare una variabile tipizzata id per fare riferimento a un object. Utilizza il riferimento digitato di class più specifico che puoi. Anche NSObject * è migliore di id perché il compilatore può, quantomeno, fornire una migliore convalida delle invocazioni del metodo rispetto a quel riferimento.

L’unico uso comune e valido di void * è un riferimento dati opaco che viene passato attraverso altre API.

Considera sortedArrayUsingFunction: context: metodo di NSArray :

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

La funzione di ordinamento sarebbe dichiarata come:

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

In questo caso, il NSArray passa semplicemente tutto ciò che si passa come argomento di context al metodo come argomento di context . Si tratta di un pezzo opaco di dati di dimensioni puntatore, per quanto riguarda NSArray, e sei libero di usarlo per qualsiasi scopo tu voglia.

Senza una caratteristica del tipo di chiusura nella lingua, questo è l’unico modo per portare con sé un pezzo di dati con una funzione. Esempio; se si desidera che mySortFunc () esegua l’ordinamento condizionale con distinzione tra maiuscole e minuscole o maiuscole e minuscole, pur rimanendo sicuro per i thread, si passa l’indicatore di maiuscole e minuscole nel contesto, probabilmente il lancio è in entrata e in uscita.

Fragile e sobject a errori, ma l’unico modo.

I blocchi risolvono questo problema – I blocchi sono chiusure per C. Sono disponibili in Clang – http://llvm.org/ e sono diffusi in Snow Leopard ( http://developer.apple.com/library/ios/documentation/Performance /Reference/GCD_libdispatch_Ref/GCD_libdispatch_Ref.pdf ).

id è un puntatore a un object C oggettivo, dove come void * è un puntatore a qualsiasi cosa.

id distriggers anche gli avvisi relativi alla chiamata di metodi sconosciuti, quindi ad esempio:

[(id)obj doSomethingWeirdYouveNeverHeardOf];

non darò il solito avvertimento sui metodi sconosciuti. Ovviamente, genererà un’eccezione in fase di esecuzione a meno che obj non sia nullo o implementa effettivamente tale metodo.

Spesso dovresti usare NSObject* o id preferibilmente a id , che almeno conferma che l’object restituito è un object Cocoa, quindi puoi tranquillamente usare metodi come retain / release / autorelease su di esso.

Se un metodo ha un tipo di id di ritorno, è ansible restituire qualsiasi object Objective-C.

void significa, il metodo non restituirà nulla.

void * è solo un puntatore. Non sarai in grado di modificare il contenuto dell’indirizzo a cui punta il puntatore.

id è un puntatore a un object Objective-C. void * è un puntatore a qualsiasi cosa . Potresti usare void * invece di id , ma non è consigliato perché non riceverai mai avvisi del compilatore per nulla.

Potresti voler vedere stackoverflow.com/questions/466777/whats-the-difference-tra-declaring-a-variable-id-and-nsobject e 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; 

Il codice di cui sopra è da objc.h, così come id è un’istanza di objc_object struct e isa pointer può collegarsi con qualsiasi object Objective Classe C, mentre void * è solo un puntatore non tipizzato.

La mia comprensione è che id rappresenta un puntatore a un object mentre void * può puntare a qualcosa in realtà, purché tu lo lanci al tipo che vuoi usarlo come

Oltre a quanto già detto, c’è una differenza tra oggetti e puntatori relativi alle collezioni. Per esempio, se vuoi mettere qualcosa in NSArray, hai bisogno di un object (di tipo “id”), e non puoi usare un puntatore di dati grezzi lì (di tipo “void *”). È ansible utilizzare [NSValue valueWithPointer:rawData] per convertire void *rawDdata nel tipo “id” per utilizzarlo all’interno di una raccolta. In generale “id” è più flessibile e ha più semantica legata agli oggetti ad essa associati. Ci sono altri esempi che spiegano il tipo di id dell’objective C qui .