Objective C中的id和NSObject有什么不同?

Tat*_*tat 12 objective-c

这有什么不同:

ID:

#import <objc/Object.h>

@interface Forwarder : Object
{
    id something;
}
Run Code Online (Sandbox Code Playgroud)

NSObject的:

#import <objc/Object.h>

@interface Forwarder : Object
{
    NSObject *something;
}
Run Code Online (Sandbox Code Playgroud)

你呢.

Von*_*onC 16

这篇来自unixjunkie博客的Greg MILLER博客文章 总结了这些差异

一些提取物:

关于Objective-C中以下三个声明之间的区别经常存在混淆:

id foo1;
NSObject *foo2;
id<NSObject> foo3;
Run Code Online (Sandbox Code Playgroud)
  • 第一个是最常见的.
    它只是声明一个指向某个Objective-C对象的指针(请参阅参考资料/usr/include/objc/objc.h).id为编译器提供了有关对象实际类型的信息,因此编译器无法为您进行编译时类型检查.

  • 仅仅因为我们知道id是Objective-C对象并不意味着它指向一个派生自的对象NSObject,或者它甚至具有诸如retain和release之类的常用方法.
    一种解决方案是静态输入我们的变量NSObject*,如上面的数字2所示.
    这为编译器提供了有关foo2指向的对象类的信息,因此编译器可以发出警告,如果你向foo2发送一个NSObject没有响应的消息.这意味着您可以安全地调用保留,释放,描述等,但如果您调用长度或计数或任何NSObject不响应的内容,编译器将发出警告.

  • 声明一个对象id<NSObject>告诉编译器您不关心该对象的类型,但您确实知道它符合指定的NSObject协议**.
    **protocol(@protocol)命名NSObject.还有一个名为NSObject确实符合NSObject协议的类,但它们是两个不同的东西
    编译器将确保您分配给该指针的所有对象符合所需的协议.
    像这样输入的指针可以安全地保存任何指针NSObject(因为NSObject符合NSObject协议),但它也可以保存任何指针NSProxy,因为它NSProxy也符合NSObject协议.
    在英语中,声明id<NSObject>foo3; 说"foo3是指向任何类型的对象的指针,其行为类似于NSObject".
    这是非常强大,方便和富有表现力的.实际上,我们通常不关心对象是什么类型,我们只关心它响应我们想要发送它的消息(例如,保留,释放).


如果您不想(或不能)进行任何类型检查,请使用普通ID.对于不知道它们返回的对象类型的方法的返回类型(例如,+ alloc),这是很常见的.将委托声明为类型id也很常见,因为委托通常在运行时使用respondsToSelector:进行检查,并且通常不会保留委托.

但是,如果您确实需要编译时类型检查,则必须在第二种和第三种情况之间做出决定.好吧,让我帮助你 - 你想要第三种情况!:-)我非常,非常非常罕见地看到NSObject*工作的情况但是id不会.使用协议形式的优点是它可以与NSProxys一起使用.