Чем отличается идентификатор от NSObject в Задаче C? - PullRequest
12 голосов
/ 23 мая 2010

В чем разница между:

Идентификатор:

#import <objc/Object.h>

@interface Forwarder : Object
{
    id something;
}

NSObject:

#import <objc/Object.h>

@interface Forwarder : Object
{
    NSObject *something;
}

Thz u.

Ответы [ 3 ]

16 голосов
/ 23 мая 2010

Это сообщение в блоге Грега Миллера из блога unixjunkie подводит итог различия

Некоторые экстракты:

Часто возникает путаница в разнице между следующими тремя объявлениями в Objective-C:

id foo1;
NSObject *foo2;
id<NSObject> foo3;
  • Первый является наиболее распространенным.
    Он просто объявляет указатель на некоторый объект Objective-C (см. /usr/include/objc/objc.h). id не дает компилятору никакой информации о фактическом типе объекта, поэтому компилятор не может выполнить проверку типов во время компиляции.

  • То, что мы знаем, что id является объектом Objective-C, не означает, что он указывает на объект, производный от NSObject, или что у него даже есть общие методы, такие как retain и release.
    Одно из решений состоит в том, чтобы статически напечатать нашу переменную, используя NSObject*, как показано в номере 2 выше. Это дает компилятору информацию о классе объекта, на который указывает foo2, поэтому компилятор может предупредить, если вы отправите сообщение в foo2, на которое NSObject не отвечает. Это означает, что вы можете безопасно вызывать retain, release, description и т. Д., Но компилятор предупредит, если вы вызовете length или count или что-то, на что NSObject не отвечает.

  • Объявление объекта как id<NSObject> говорит компилятору, что вам все равно, какой это тип объекта, но вам важно, чтобы он соответствовал указанному NSObject протоколу **.
    ** протокол (@protocol) с именем NSObject. Существует также класс с именем NSObject, который действительно соответствует протоколу NSObject, но это две разные вещи
    Компилятор гарантирует, что все объекты, которые вы назначаете этому указателю, соответствуют требуемому протоколу.
    Указатель, напечатанный таким образом, может безопасно содержать любой NSObject (поскольку NSObject соответствует протоколу NSObject), но он также может содержать любой NSProxy, поскольку NSProxy также соответствует протоколу NSObject.
    На английском языке объявление id<NSObject> foo3; говорит «foo3 - указатель на объект любого типа, который ведет себя как объект NSObject».
    Это очень мощно, удобно и выразительно. В действительности, нам часто не важно, какой тип объекта, мы просто заботимся о том, чтобы он отвечал на сообщения, которые мы хотим отправить (например, сохранить, освободить).


Если вы не хотите (или не можете иметь) проверку типов, используйте простой идентификатор. Это очень распространено для возвращаемых типов в методах, которые не знают тип возвращаемого объекта (например, + alloc). Также обычно объявляют делегатов как идентификаторы типа, потому что делегаты обычно проверяются во время выполнения с помощью responsedsToSelector:, и они обычно не сохраняются.

Однако, если вы хотите проверить тип во время компиляции, вы должны выбрать между вторым и третьим случаями. Хорошо, позвольте мне помочь вам - вы хотите третий случай! :-) Я очень, очень, ОЧЕНЬ редко видел ситуацию, когда NSObject * работал, но id - нет. Преимущество использования формы протокола в том, что она будет работать с NSProxys.

3 голосов
/ 23 мая 2010

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

1 голос
/ 23 мая 2010

Идентификатор отвечает на любой метод без предупреждения компилятора; NSObjects отвечают без предупреждения только на методы, определенные в NSObject, включая протокол NSObject.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...