为什么使用id,当我们可以只使用NSObject?

我知道,当我们想创build一个未知的值对象,我们使用ID。 不过,我很好奇,为什么苹果select在运行时决定它的值的id,当时每个对象都是NSObject的子类。 所以,而不是id delegate我们可以使用NSObject *delegate有谁知道为什么? 谢谢。

id擦除types,相当于说“这个对象响应翻译可见的select器”。 当然,当你擦除types时(以及当你input它们的时候), 你有责任确保你的程序是正确的。

如果types是NSObject ,那么如果select器没有在NSObject的接口或它所采用的协议中声明,编译器会说“NSObject可能不响应select器 ”。 在这种情况下,您也可以添加一个types转换来将其转换为您所期望的types。

使用严格/正确的types,编译器可以踢出来帮助你,这很好,因为ObjC是一种非常dynamic的语言。

id在使用(或构build)集合types时特别有用。 添加一个对象不会是一个问题,除非你定义了一个新的根types(不从NSObjectinheritance)。 从集合中获取值需要一个types转换(typecast),如果我们要把它作为基类(NSObject)之外的东西来使用的话。

Objective-C不支持generics – 例如,你不能声明NSStringNSArray 。 你可以使用NSString填充一个NSArray ,并且在types安全性不被保留的情况下(lagenerics),通过id传递一个更自然的书面风格。

所以,让我们用一些真实的代码来展开。

例子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; 

每个对象都是NSObject的一个子类

这是一个不正确的说法。 您可以创build不从NSObjectinheritance的对象。 这不是真的推荐,但它是可能的。

NSProxy是一个例子 – 它不从NSObjectinheritance。

 typedef struct objc_object { Class isa; } *id; 

以上是Objective-C语言中id的实际定义。 Objective-C运行时系统是围绕idClass构build的。 没有什么必须与NSObject或普通的超类。

http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/ObjectiveC/Chapters/ocObjectsClasses.html#//apple_ref/doc/uid/TP30001163-CH11-SW3

NSObject类

NSObject是一个根类,所以没有超类。 它定义了Objective-C对象和对象交互的基本框架。 它赋予类inheritance的类和实例的能力,作为对象的行为,并与运行时系统合作。

不需要从另一个类inheritance任何特殊行为的类应该成为NSObject类的一个子类。 类的实例必须至less具有在运行时类似于Objective-C对象的能力。 从NSObject类inheritance这个function比在新的类定义中重新创build它要简单得多,也更可靠。

我想,这是因为它最初是C而不是C++ (或其他更严格的打字语言)。

每个对象都是NSObject的一个子类

这是不正确的。 你可以创build一个从根本上没有任何东西的对象。

这也许是为什么id被介绍了。