为什么在我们可以使用NSObject时使用id?

时间:2011-10-26 14:14:57

标签: objective-c cocoa class types polymorphism

我知道当我们想要创建一个未知值对象时,我们使用id。但是,我很好奇Apple为什么选择id在运行时决定它的值,当每个对象都是NSObject的子类时。因此,我们可以使用id delegate而不是NSObject *delegate有人知道为什么吗?感谢。

4 个答案:

答案 0 :(得分:39)

id删除类型,它相当于说“此对象响应翻译可见的任何选择器”。当然,当你删除类型时(以及当你对它们进行类型转换时),确保你的程序是正确的是的责任。

如果类型是NSObject,那么如果选择器未在NSObject的接口或它采用的协议中声明,编译器会说“NSObject可能不响应选择器”。在这种情况下,您还可以添加类型转换以将其强制转换为您期望的类型。

使用严格/正确的类型,编译器可以启动并帮助你,这很好,因为ObjC是一种非常动态的语言。

id在使用(或构建)集合类型时特别有用。除非您定义了新的根类型(不从NSObject继承),否则添加对象不会有问题。如果我们将它作为基类(NSObject)之外的其他东西使用,那么从集合中获取值将需要类型转换。

Objective-C不支持泛型 - 例如,您不能声明NSArray NSString的{​​{1}}。您可以使用NSArray填充NSString并通过id传递此内容,以便在未保留类型安全性时使用更自然的书面样式(la generics)。

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

示例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 with protocols:

NSObject<MONShapeDelegate>* delegate;

答案 1 :(得分:11)

  

每个对象都是NSObject的子类

这是一个不正确的陈述。您可以创建不从NSObject继承的对象。它并不是真的推荐,但它是可能的。

NSProxy是一个例子 - 它不会从NSObject继承。

答案 2 :(得分:3)

typedef struct objc_object {
    Class isa;
} *id;

以上是Objective-C语言中id的实际定义。 Objective-C运行时系统围绕idClass构建。没有什么与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对象和对象交互的基本框架。   它赋予继承的类的类和实例   它具有表现为对象并与运行时协作的能力   系统

     

不需要从另一个继承任何特殊行为的类   尽管如此,class仍应成为NSObject类的子类。   该类的实例必须至少具有行为的能力   运行时的Objective-C对象。从。继承此功能   NSObject类比重新发明更简单,更可靠   它在一个新的类定义中。

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

答案 3 :(得分:2)

  

每个对象都是NSObject的子类

这不正确。你可以创建一个从无任何扩展的对象作为根类。

这也许就是id被引入的原因。