Я знаю, что когда мы хотим создать неизвестный объект значения, мы используем id. Однако мне любопытно, почему Apple выбрала идентификатор, который определяет его значение во время выполнения, когда каждый объект является подклассом NSObject. Поэтому вместо id delegate
мы могли бы использовать NSObject *delegate
Кто-нибудь знает, почему? Спасибо.
Зачем использовать id, когда мы можем просто использовать NSObject?
Ответ 1
id
стирает тип, и он эквивалентен тому, что "этот объект отвечает на любой селектор, видимый для перевода". конечно, вы несете ответственность за то, чтобы ваша программа была правильной, когда вы удаляете типы (а также при их отображении).
Если тип был NSObject
, тогда компилятор сказал бы: "NSObject может не отвечать на селектор", если селектор не был объявлен в интерфейсе NSObject или протоколах, которые он принимает. В этом случае вы также можете добавить приведение типов к тому, что вы ожидаете.
Со строгими/правильными типами компилятор может ударить и помочь вам, что отлично, потому что ObjC - очень динамичный язык.
id
особенно полезен при использовании (или создании) типов коллекций. Добавление объекта не будет проблемой, если вы не определили новый корневой тип (не наследуемый от NSObject). Получение значения из коллекции потребует машинного перевода, если мы будем использовать его как нечто иное, чем наш базовый класс (NSObject).
Objective-C не поддерживает дженерики - вы не можете, например, объявить NSArray
из NSString
s. Вы можете заполнить NSArray
с помощью NSString
и передать это через id
для более естественного письменного стиля, когда безопасность типов не сохраняется (a la generics).
Итак, давайте разберем это с помощью некоторого реального кода.
Пример A
NSString * string = [array objectAtIndex:0]; // << trust me (via id)
return [string length];
-or-
return [[array objectAtIndex:0] length]; // << trust me (via id)
Пример B
А теперь скажем, id
недоступен, и мы исправим все наши предупреждения для компилятора, потому что это правильно:
NSString * string = (NSString*)[array objectAtIndex:0]; // << typecast == trust me
return [string length];
-or-
return [(NSString*)[array objectAtIndex:0] length]; // << typecast == trust me
id
не определяет его значение во время выполнения, а также не NSObject. Объекты ObjC не выполняют неявных рекламных акций, они просто передают указатель без официального продвижения.
В связи с вашим примером я фактически объявляю свои делегаты и параметры как NSObjects с протоколами:
NSObject<MONShapeDelegate>* delegate;
Ответ 2
каждый объект является подклассом NSObject
Это неверное утверждение. Вы можете создавать объекты, которые не наследуются от NSObject. это не рекомендуется, но это возможно.
NSProxy
- пример - он не наследуется от NSObject.
Ответ 3
typedef struct objc_object {
Class isa;
} *id;
Выше приведено фактическое определение id
в Objective-C языке. Objective-C система времени выполнения построена вокруг id
и Class
. Ничто не связано с NSObject или обычным суперклассом.
Класс NSObject
NSObject - это корневой класс, и поэтому он не имеет суперкласса. Он определяет базовую структуру для объектов Objective-C и взаимодействия объектов. Он передает классы и экземпляры классов, которые наследуются от это способность вести себя как объекты и сотрудничать со временем выполнения система.
Класс, который не должен наследовать какое-либо особое поведение от другого класс должен, тем не менее, быть подклассом класса NSObject. Экземпляры класса должны по крайней мере иметь способность вести себя как Objective-C объектов во время выполнения. Унаследовать эту способность от Класс NSObject намного проще и надежнее, чем переосмысление это в новом определении класса.
Я думаю, это потому, что изначально он был C
not C++
(или других более строгих языков ввода).
Ответ 4
каждый объект является подклассом NSObject
Это не правильно. Вы можете создать объект, который не является ничем как корневой класс.
Возможно, поэтому был введен id.