Objective-C: разница между id и void *

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

Ответ 1

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).

Ответ 2

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

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

[(id)obj doSomethingWeirdYouveNeverHeardOf];

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

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

Ответ 3

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

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

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

Ответ 4

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

Возможно, вы захотите увидеть fooobar.com/questions/35965/... и unixjunkie.blogspot.com/2008/03/id-vs-nsobject-vs-id.html.

Ответ 5

/// 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 Class, а void * - это просто нетипизированный указатель.

Ответ 6

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

Ответ 7

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