В чем разница между объявлением переменной "id" и "NSObject *"? - PullRequest
44 голосов
/ 21 января 2009

В Objective-C, в чем разница между объявлением переменной id и объявлением ее NSObject *?

Ответы [ 4 ]

51 голосов
/ 21 января 2009

С помощью переменной id вы можете отправить ей любое известное сообщение, и компилятор не будет жаловаться. С переменной типа NSObject * вы можете отправлять ей только сообщения, объявленные NSObject (но не методы какого-либо подкласса), иначе оно выдаст предупреждение. В общем, id это то, что вы хотите.

Дальнейшее объяснение: Все объекты по существу имеют тип id. Смысл объявления статического типа заключается в том, чтобы сказать компилятору: «Предположим, что этот объект является членом этого класса». Поэтому, если вы отправите ему сообщение, которое класс не объявляет, компилятор может сказать вам: «Подождите, этот объект не должен получить это сообщение!» Кроме того, если два класса имеют методы с одним и тем же именем, но разными сигнатурами (то есть тип аргумента или возвращаемый тип), он может угадать, какой метод вы подразумеваете под классом, объявленным для переменной. Если он объявлен как id, компилятор просто поднимет руки и скажет: «Хорошо, у меня недостаточно информации. Я выбираю сигнатуру метода случайным образом». (Однако, как правило, это не поможет объявлением NSObject*. Обычно конфликт происходит между двумя более конкретными классами.)

17 голосов
/ 21 января 2009

id означает «объект», NSObject * означает «экземпляр NSObject или один из его подклассов». В Objective-C есть объекты, которые не NSObject s (те, которые вы встретите в Какао в данный момент, это NSProxy, Protocol и Class). Если какой-то код ожидает объект определенного класса, объявление, которое помогает компилятору проверить, правильно ли вы его используете. Если вы действительно можете взять «любой объект» - например, вы объявляете делегата и будете проверять все посылки метода с respondsToSelector: вызовами - вы можете использовать id.

Другой способ объявить объектную переменную похож на «id <NSObject>», что означает «любой объект, реализующий протокол NSObject.

10 голосов
/ 22 января 2009

Из моего ограниченного понимания Objective-C не все объекты являются производными от NSObject (в отличие от Java, где все объекты являются производными от Object). Теоретически вы можете иметь другие корневые объекты. id может применяться к любому из этих не производных от NSObject объектов.

0 голосов
/ 19 ноября 2014

Я хотел бы добавить еще одно отличие. Когда вы добавляете протокол к id, это больше не означает, что он будет иметь тип NSObject *, это просто означает, что это будет любой класс, который подтверждает этот протокол.

Так, например, этот код не выдаст никакой ошибки, так как NSDelayedPerforming в категории *1006* имеет такой метод:

id testId;
[testId performSelector:@selector(isKindOfClass:) withObject:[NSObject class] afterDelay:.5];

Однако этот код покажет ошибку No known instance method for selector "performSelector:withObject:afterDelay:":

id<NSMutableCopying> testId;
[testId performSelector:@selector(isKindOfClass:) withObject:[NSObject class] afterDelay:.5];
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...