当我们只能使用 NSObject 时,为啥还要使用 id?
Posted
技术标签:
【中文标题】当我们只能使用 NSObject 时,为啥还要使用 id?【英文标题】:Why use id when we can just use NSObject?当我们只能使用 NSObject 时,为什么还要使用 id? 【发布时间】:2011-12-15 18:42:53 【问题描述】:我知道当我们想要创建一个未知的值对象时,我们会使用 id。但是,我很好奇为什么 Apple 选择 id 来决定它在运行时的值,当每个对象都是 NSObject 的子类时。所以我们可以使用NSObject *delegate
而不是id delegate
有人知道为什么吗?谢谢。
【问题讨论】:
NSProxy 是 cocoa 提供的另一个根类。 NSObject 包含 isa 指针,id 没有。看看***.com/a/19634973/944634 什么哈哈? id 是一个 isa 指针。 ***.com/questions/1990695/… 【参考方案1】:id
删除类型,相当于说“此对象响应任何对翻译可见的选择器”。当然,您有责任确保您的程序在擦除类型时(以及在类型转换时)是正确的。
如果类型是NSObject
,那么如果选择器没有在 NSObject 的接口或它采用的协议中声明,编译器会说“NSObject 可能无法响应 selector”。在这种情况下,您还可以添加一个类型转换以将其转换为您期望的类型。
使用严格/正确的类型,编译器可以启动并帮助您,这很棒,因为 ObjC 是一种非常动态的语言。
id
在使用(或构建)集合类型时特别有用。除非您定义了新的根类型(不继承自 NSObject),否则添加对象不会有问题。如果我们要将集合用作基类 (NSObject) 以外的东西,则从集合中获取值需要进行类型转换。
Objective-C 不支持泛型 - 例如,您不能声明 NSArray
或 NSString
s。您可以使用NSString
s 填充NSArray
,并将其传递给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每个对象都是 NSObject 的子类
这是一个错误的说法。您可以创建不继承自 NSObject 的对象。不是很推荐,但有可能。
NSProxy
是一个示例 - 它不继承自 NSObject。
【讨论】:
这只是我的答案的克隆! 对不起:/我在没有答案的时候写了它,你打败了我......没有难过的感觉,也不需要投反对票......另外,你没有提到NSProxy
...
如果它是一个堆栈并且这个答案在底部,那么@Jasarien 首先回答;)
@beryl:答案的默认显示顺序按投票总数进行分类,然后在每一层中随机排列。如果您真的想知道确切的发布时间,“X 小时前已回答”附带了一个工具提示,它将为您提供时间戳。您还可以点击答案部分顶部的“最旧”选项卡,按发布日期对答案进行排序。
在将近七年后也许不值得一提,但是:回答问题并不是纠正问题中事实错误的正确方法。你应该评论这个问题,甚至重写它。【参考方案3】:
typedef struct objc_object
Class isa;
*id;
以上是Objective-C语言中id
的实际定义。 Objective-C 运行时系统是围绕id
和Class
构建的。与 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 对象和对象交互的基本框架。 它赋予继承自的类和类的实例 它能够像对象一样运行并与运行时协作 系统。
不需要从另一个类继承任何特殊行为的类 尽管如此,类仍应成为 NSObject 类的子类。 类的实例必须至少有能力表现得像 运行时的 Objective-C 对象。 从 NSObject 类比重新发明更简单,更可靠 它在一个新的类定义中。
我认为,这是因为它最初是 C
而不是 C++
(或其他更严格的打字语言)。
【讨论】:
【参考方案4】:每个对象都是 NSObject 的子类
这是不正确的。您可以创建一个从无到有的对象作为根类。
这也许就是引入 id 的原因。
【讨论】:
以上是关于当我们只能使用 NSObject 时,为啥还要使用 id?的主要内容,如果未能解决你的问题,请参考以下文章
当我们可以不用 BETWEEN 运算符时,为啥还要使用它呢?
当我们可以在 awakeFromNib 中转储所有内容时,为啥还要使用 init(coder)?