В чем разница между id и NSObject в Objective C?

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

ID:

#import <objc/Object.h>

@interface Forwarder : Object
{
    id something;
}

NSObject:

#import <objc/Object.h>

@interface Forwarder : Object
{
    NSObject *something;
}

Thz u.

Ответ 1

Это сообщение в блоге Greg MILLER из unixjunkie blog суммирует различия

Некоторые выдержки:

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

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

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

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


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

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

Ответ 2

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

Ответ 3

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