Ответ 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).