Цель-C: разница между id и void *
В чем разница между id
а также void *
?
7 ответов
void *
означает "ссылка на некоторый случайный фрагмент памяти с нетипизированным / неизвестным содержимым"
id
означает "ссылка на некоторый случайный объект Objective-C неизвестного класса"
Есть дополнительные семантические различия:
В режимах GC Only или GC Supported компилятор будет создавать барьеры записи для ссылок типа
id
, но не для типаvoid *
, При объявлении структур это может быть критической разницей. Объявление iVars какvoid *_superPrivateDoNotTouch;
приведет к преждевременному пожатию объектов, если_superPrivateDoNotTouch
на самом деле объект. Не делай этого.пытаясь вызвать метод по ссылке
void *
type сожжет предупреждение компилятора.пытаясь вызвать метод на
id
Тип будет только предупреждать, если вызываемый метод не был объявлен ни в одном из@interface
объявления, видимые компилятором.
Таким образом, никогда не следует ссылаться на объект как на void *
, Точно так же следует избегать использования id
типизированная переменная для ссылки на объект. Используйте наиболее конкретную типизированную ссылку класса, которую вы можете. Четное NSObject *
лучше, чем id
потому что компилятор может, по крайней мере, обеспечить лучшую проверку вызовов методов для этой ссылки.
Одно общее и правильное использование void *
как непрозрачная ссылка на данные, которая передается через какой-то другой API.
Рассмотрим sortedArrayUsingFunction: context:
метод NSArray
:
- (NSArray *)sortedArrayUsingFunction:(NSInteger (*)(id, id, void *))comparator context:(void *)context;
Функция сортировки будет объявлена как:
NSInteger mySortFunc(id left, id right, void *context) { ...; }
В этом случае NSArray просто передает все, что вы передаете, как context
аргумент метода через как context
аргумент. Это непрозрачный кусок данных размером с указатель, что касается NSArray, и вы можете использовать его для любых целей.
Без функции типа замыкания в языке это единственный способ перенести часть данных с функцией. Пример; если бы вы хотели, чтобы mySortFunc() выполняла условную сортировку как чувствительную к регистру или нечувствительную к регистру, так и сохраняя при этом многопоточность, вы бы пропустили индикатор чувствительности к регистру в контексте, что, вероятно, приводит к входу и выходу.
Хрупкие и подверженные ошибкам, но единственный способ.
Блоки решают эту проблему - блоки являются замыканиями для C. Они доступны в Clang - http://llvm.org/ и распространены в Snow Leopard ( http://developer.apple.com/library/ios/documentation/Performance/Reference/GCD_libdispatch_Ref/GCD_libdispatch_Ref.pdf).
id - это указатель на целевой объект C, где void* - указатель на что-либо.
id также отключает предупреждения, связанные с вызовом неизвестных mthods, например:
[(id)obj doSomethingWeirdYouveNeverHeardOf];
не даст обычного предупреждения о неизвестных методах. Это, конечно, вызовет исключение во время выполнения, если obj не равен nil или действительно не реализует этот метод.
Часто вы должны использовать NSObject*
или же id<NSObject>
в предпочтении id
, что по крайней мере подтверждает, что возвращаемый объект является объектом Какао, так что вы можете безопасно использовать такие методы, как retain/release/autorelease.
id
указатель на объект Objective-C void *
это указатель на что-нибудь. Вы могли бы использовать void *
вместо id
, но это не рекомендуется, потому что вы никогда не получите предупреждения компилятора ни за что.
Вы можете захотеть увидеть /questions/31148599/v-chem-raznitsa-mezhdu-obyavleniem-peremennoj-id-i-nsobject и http://unixjunkie.blogspot.com/2008/03/id-vs-nsobject-vs-id.html.
Если метод имеет возвращаемый тип id
Вы можете вернуть любой объект Objective-C.
void
значит, метод ничего не вернет.
void *
это просто указатель. Вы не сможете редактировать содержимое по адресу, на который указывает указатель.
/// 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;
Приведенный выше код взят из objc.h, поэтому похоже, что id является экземпляром структуры objc_object, и указатель is a может связываться с любым объектом класса Objective C, а void* - просто нетипизированный указатель.
Насколько я понимаю, id представляет собой указатель на объект, в то время как void * может указывать на что-либо на самом деле, при условии, что вы приведете его к типу, который хотите использовать как
В дополнение к тому, что уже сказано, есть различие между объектами и указателями, связанными с коллекциями. Например, если вы хотите поместить что-то в NSArray, вам нужен объект (типа "id"), и вы не можете использовать там указатель необработанных данных (типа "void *"). Ты можешь использовать [NSValue valueWithPointer:rawData]
преобразовать void *rawDdata
к типу "ID" для использования его внутри коллекции. В общем, "id" более гибок и имеет больше семантики, связанной с объектами, прикрепленными к нему. Есть больше примеров, объясняющих тип идентификатора Objective C здесь.