今天 allen 问了我一个问题,id
和NSObject
之间有什么区别,经过大神henry指点给我这个网址 id vs NSObject* vs id<NSObject>,大致明白其中的原理。
id foo1;
NSObject *foo2;
id<NSObject> *foo3;
-
id
在实际编码中,我们经常看到第一个,在编译器眼中,id
仅仅意味着一个指向对象的指针,关于这个对象的信息,编译器需要等到runtime才能确定。因此,在程序中,不管对由id指向的对象发送任何消息,编译器都不会有任何报错,就像我们常见的id obj = [[Foo alloc] init]
一样,由于Foo alloc
返回的是id
对象,因此对其调用init
方法与对其调用initWithbalbalbal
等方法都是可以的(当然,现在的编译器会只能地警告,之前没见过这个selector
)。 -
NSObject
而id
指向的对象并不全是NSObject
的子类,当我们指定一个类为NSObject
时,编译器就确切地知道了该类的所有信息,因此,当我们对该对象发送NSObject
没有声明的方法时,编译器就会果断报错 = =
在别的语言中,声明一个类似NSObject
的对象并进行操作是非常普遍的,因为NSObject
意味着所有类的基类,但在objc这门动态语言中,过于严格的类型检查是不受欢迎的,在框架中,并不是所有类都继承自NSObject
,比如说NSProxy
,尽管它声明了大多数与NSObject
同样的方法,但它的基类并不是NSObject
,这时候,id<NSObject>
就发挥出作用了。 -
id<NSObject>
将一个对象声明为id<NSObject>
,意味着编译器不对其作任何类型检查,但是这个对象所属的类默认实现名为NSObject
的protrol(是的,也有一个协议叫NSObject
)。其实,在实际操作中,我们往往不会去关心一个对象的所属的类,而是这个对象会响应什么方法,id<NSObject>
表明了foo3
这个指针指向了一个实现了NSObject
协议的方法的类的对象。
因此我们应该在这三种方法中做出怎么样的选择呢,如果你是需要一个不需要任何类型检查的对象指针时,就使用 id
吧,它经常用于接收一些不确定返回值类型的函数返回值,也经常用于 delegate
上,因为在runtime时,delegate
所属的类并不重要,而是会通过 responseToSelector:
做对其相应的方法做检查。(当然也可能是通过协议指定)。
而当你需要一个严格类型检查的对象指针时,相信我,使用 id<NSObject>
吧~因为在现有框架中,我们会大量使用 NSProxy
,这个不属于 NSObject
子类的东东,并且,我们只需要确认一个对象能用响应一系列 NSObject
的方法,我们根本不关系它所属的类。