Цель-C: разница между id и void * - PullRequest
167 голосов
/ 20 августа 2009

В чем разница между id и void *?

Ответы [ 7 ]

234 голосов
/ 20 августа 2009

void * означает «ссылку на некоторый случайный фрагмент памяти с нетипизированным / неизвестным содержимым»

id означает «ссылку на некоторый случайный объект Objective C неизвестного класса»

Существуют дополнительные смысловые различия:

  • В режимах GC Only или GC Supported компилятор будет создавать барьеры записи для ссылок типа id, но не для типа void *. При объявлении структур это может быть критическим различием. Объявление iVars как void *_superPrivateDoNotTouch; приведет к преждевременному пожатию объектов, если _superPrivateDoNotTouch на самом деле является объектом. Не делай этого.

  • попытка вызвать метод по ссылке типа void * вызовет предупреждение компилятора.

  • попытка вызвать метод типа 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).

19 голосов
/ 20 августа 2009

id - указатель на объект C, где void * - указатель на что-либо.

id также отключает предупреждения, связанные с вызовом неизвестных методов, например:

[(id)obj doSomethingWeirdYouveNeverHeardOf];

не выдаст обычного предупреждения о неизвестных методах. Конечно, он вызовет исключение во время выполнения, если obj не равен nil или действительно не реализует этот метод.

Часто вы должны использовать NSObject* или id<NSObject> вместо id, что по крайней мере подтверждает, что возвращаемый объект является объектом Какао, поэтому вы можете безопасно использовать такие методы, как retain / release / autorelease. 1013 *

8 голосов
/ 20 августа 2009

Если у метода есть тип возврата id, вы можете вернуть любой объект Objective-C.

void означает, что метод ничего не вернет.

void * это просто указатель. Вы не сможете редактировать содержимое по адресу, на который указывает указатель.

7 голосов
/ 20 августа 2009

id - указатель на объект Objective-C. void * - указатель на что-нибудь . Вы можете использовать void * вместо id, но это не рекомендуется, потому что вы никогда не получите предупреждений компилятора ни о чем.

Возможно, вы захотите увидеть stackoverflow.com / questions / 466777 / что такое разница между объявлением переменной-id-and-nsobject и unixjunkie.blogspot.com /2008/03/id-vs-nsobject-vs-id.html.

4 голосов
/ 19 января 2015
/// 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, и указатель isa может связываться с любым объектом класса Objective C, тогда как void * является просто нетипизированным указателем.

2 голосов
/ 20 августа 2009

Насколько я понимаю, id представляет собой указатель на объект, а void * может указывать на что-либо действительно, если вы затем приведете его к типу, который хотите использовать как

0 голосов
/ 30 апреля 2016

В дополнение к тому, что уже сказано, есть различие между объектами и указателями, связанными с коллекциями. Например, если вы хотите поместить что-то в NSArray, вам нужен объект (типа "id"), и вы не можете использовать указатель необработанных данных (типа "void *"). Вы можете использовать [NSValue valueWithPointer:rawData] для преобразования void *rawDdata в тип "id", чтобы использовать его внутри коллекции. В общем, «id» более гибок и имеет больше семантики, связанной с объектами, прикрепленными к нему. Здесь больше примеров, объясняющих идентификатор типа Objective C .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...