В чем разница между объявлением переменной "id" и "NSObject *"?
В Objective-C, в чем разница между объявлением переменной id
по сравнению с объявлением NSObject *
?
4 ответа
С введенной переменной id
Вы можете отправить ему любое известное сообщение и компилятор не будет жаловаться. С введенной переменной NSObject *
вы можете только отправлять ему сообщения, объявленные NSObject (но не методы какого-либо подкласса), иначе оно выдаст предупреждение. В общем, id
это то, что вы хотите.
Дальнейшее объяснение: все объекты по существу имеют тип id
, Смысл объявления статического типа состоит в том, чтобы сказать компилятору: "Предположим, что этот объект является членом этого класса". Поэтому, если вы отправите ему сообщение, которое класс не объявляет, компилятор может сказать вам: "Подождите, этот объект не должен получить это сообщение!" Кроме того, если два класса имеют методы с одинаковыми именами, но разными сигнатурами (то есть тип аргумента или возвращаемый тип), он может угадать, какой метод вы подразумеваете под классом, который вы объявили для переменной. Если это объявлено как id
компилятор просто поднимает руки и говорит вам: "Хорошо, у меня здесь недостаточно информации. Я выбираю сигнатуру метода случайным образом". (Как правило, это не поможет NSObject*
, хоть. Обычно конфликт происходит между двумя более конкретными классами.)
id
означает "объект", NSObject *
означает "экземпляр NSObject
или один из его подклассов ". В Objective-C есть объекты, которые не являются NSObject
s (те, которые вы встретите в настоящее время в Какао, NSProxy
, Protocol
а также Class
). Если какой-то код ожидает объект определенного класса, объявление, которое помогает компилятору проверить, правильно ли вы его используете. Если вы действительно можете взять "любой объект" - например, вы объявляете делегата и будете проверять все посылки метода с respondsToSelector:
звонки - вы можете использовать id
,
Еще один способ объявить переменную объекта - это какid <NSObject>
", что означает" любой объект, который реализует NSObject
протокол.
Из моего ограниченного понимания Objective-C не все объекты являются производными от NSObject (в отличие от Java, где все объекты являются производными от Object). Теоретически вы можете иметь другие корневые объекты. id может применяться к любому из этих объектов, не являющихся NSObject.
Я хотел бы добавить еще одну разницу. Когда вы добавляете протокол к id
, это больше не означает, что он будет иметь тип NSObject *
, это просто означает, что это будет любой класс, который подтверждает этот протокол.
Так, например, этот код не будет выдавать никаких ошибок, так как NSObject
категория NSDelayedPerforming
имеет этот метод:
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];