Objective-C: diferença entre id e void *
-
19-09-2019 - |
Pergunta
O que é a diferença entre id
e void *
?
Solução
meios void *
"uma referência a algum aleatório pedaço o' memória com conteúdo sem tipo / desconhecidos"
meios id
"uma referência a um objeto Objective-C aleatória de classe desconhecida"
Existem diferenças semânticas adicionais:
-
Sob GC Apenas ou GC modos suportados, o compilador irá emitir barreiras gravação para referências de tipo
id
, mas não para o tipovoid *
. Ao declarar estruturas, esta pode ser uma diferença crítica. Declarando IVARS comovoid *_superPrivateDoNotTouch;
causará colheita prematura de objectos se_superPrivateDoNotTouch
é na verdade um objecto. Não faça isso. -
tentar chamar um método em uma referência do tipo
void *
vai vomitar-se um aviso do compilador. -
tentar chamar um método em um tipo
id
só irá alertar se o método que está sendo chamado não foi declarado em qualquer das declarações@interface
visto pelo compilador.
Assim, nunca se deve referir a um objeto como um void *
. Da mesma forma, deve-se evitar o uso de uma variável id
digitado para se referir a um objeto. Use o máximo de referência digitado classe específica que puder. Mesmo NSObject *
é melhor do que id
porque o compilador pode, pelo menos, proporcionar uma melhor validação de invocações de método contra essa referência.
A única comum e válido uso de void *
é como uma referência de dados opaco que é passado através de algum outro API.
Considere o método sortedArrayUsingFunction: context:
de NSArray
:
- (NSArray *)sortedArrayUsingFunction:(NSInteger (*)(id, id, void *))comparator context:(void *)context;
A função de classificação seria declarado como:
NSInteger mySortFunc(id left, id right, void *context) { ...; }
Neste caso, o NSArray simplesmente passa o que você passar como argumento context
ao método através como o argumento context
. É um pedaço opaca de ponteiro dimensionado dados, tanto quanto NSArray está em causa, e você está livre para usá-lo para qualquer fim que você quer.
Sem uma característica tipo de fechamento na língua, esta é a única maneira de levar consigo um pedaço de dados com uma função. Exemplo; se você queria mySortFunc () para condicionalmente tipo como insensível caso sensível ou caso, ao mesmo tempo, continua a ser thread-safe, você deve passar o indicador está-case-sensitive no contexto, provavelmente fundição sobre a forma e saída.
Frágil e sujeito a erros, mas a única maneira.
Blocos resolver este - Os blocos são fechos para C. Eles estão disponíveis em Clang - http://llvm.org/ e estão presentes em Snow Leopard ( http: / /developer.apple.com/library/ios/documentation/Performance/Reference/GCD_libdispatch_Ref/GCD_libdispatch_Ref.pdf ).
Outras dicas
id é um ponteiro para um objeto C objetiva, onde, como void * é um ponteiro para nada.
id também desliga os avisos relacionados a chamar mthods desconhecidos, assim, por exemplo:
[(id)obj doSomethingWeirdYouveNeverHeardOf];
não vai dar o aviso habitual sobre os métodos desconhecidos. Será, naturalmente, gerar uma exceção em tempo de execução, a menos que obj é nula ou realmente implementar esse método.
Muitas vezes você deve usar NSObject*
ou id<NSObject>
de preferência a id
, que pelo menos confirma que o objeto retornado é um objeto de cacau, de modo que você pode usar com segurança métodos como reter / release / disparo automático do mesmo.
Se um método tem um tipo de retorno de id
você pode devolver qualquer objeto Objective-C.
meios void
, o método não retornará nada.
void *
é apenas um ponteiro. Você não será capaz de editar o conteúdo no endereço o ponteiro aponta para.
id
é um apontador para um objecto Objectivo-C. void *
é um ponteiro para qualquer . Você poderia usar void *
vez de id
, mas não é recomendado porque você nunca conseguiria avisos do compilador para qualquer coisa.
Você pode querer ver stackoverflow.com/ questões / 466777 / o que está-the-diferença, entre-declarando-a-variável-id-e-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;
O código de cima é de objc.h, assim como a aparência do ID é um exemplo da estrutura e objc_object ponteiro isa pode ligar-se com qualquer objeto Objectivo da Classe C, enquanto void * é apenas um ponteiro sem tipo.
O meu entendimento é que id representa um ponteiro para um objeto enquanto void * pode apontar realmente a qualquer coisa, contanto que você, em seguida, convertê-lo para o tipo que você quiser usá-lo como
Para além do que já disse, há uma diferença entre objetos e ponteiros ligadas à cobrança. Por exemplo, se você quiser colocar algo em NSArray, você precisa de um objeto (do tipo "id"), e você não pode usar um ponteiro de dados brutos lá (do tipo "void *"). Você pode usar [NSValue valueWithPointer:rawData]
para void *rawDdata
convertido para o tipo "id" para usá-lo dentro de uma coleção. Em "id" em geral é mais flexível e tem mais semântica relacionados a objetos ligados a ele. Há mais exemplos que explicam tipo ID de Objective C aqui .