Objective c 既然可以使用NSObject,为什么还要使用id?

Objective c 既然可以使用NSObject,为什么还要使用id?,objective-c,cocoa,class,types,polymorphism,Objective C,Cocoa,Class,Types,Polymorphism,我知道,当我们想要创建一个未知值的对象时,我们使用id。然而,我很好奇,为什么苹果在运行时选择id来决定它的值,而每个对象都是NSObject的子类。因此,我们可以使用NSObject*delegate而不是id delegate,有人知道为什么吗?谢谢 每个对象都是NSObject的子类 那是不对的。可以将从无到有扩展的对象作为根类 这可能就是引入id的原因。id删除类型,这相当于说“此对象响应翻译可见的任何选择器”。当然,您有责任确保在删除类型时(以及在键入时)程序是正确的 如果类型为NSO

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

每个对象都是NSObject的子类

那是不对的。可以将从无到有扩展的对象作为根类


这可能就是引入id的原因。

id
删除类型,这相当于说“此对象响应翻译可见的任何选择器”。当然,您有责任确保在删除类型时(以及在键入时)程序是正确的

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

对于严格/正确的类型,编译器可以启动并帮助您完成,这非常好,因为ObjC是一种非常动态的语言

id
在使用(或构建)集合类型时特别有用。除非定义了新的根类型(不从NSObject继承),否则添加对象不会有问题。如果要将集合中的值用作基类(NSObject)以外的其他对象,则需要进行类型转换

Objective-C不支持泛型-例如,您不能声明
NSString
s的
NSArray
。您可以使用
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)
id
在运行时不决定其值,也不决定任何NSObject。ObjC对象不执行隐式提升,它们只是在没有正式提升的情况下投射指针

与您的示例相关,我实际上使用协议将委托和参数声明为NSObject:

NSObject<MONShapeDelegate>* delegate;
NSObject*委托;
每个对象都是NSObject的子类

这是不正确的说法。您可以创建不从NSObject继承的对象。这不是真正的推荐,但它是可能的

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

typedef struct objc_object {
    Class isa;
} *id;
上面是Objective-C语言中
id
的实际定义。Objective-C运行时系统是围绕
id
Class
构建的。与NSObject或公共超类无关

NSObject类

NSObject是根类,因此没有超类。它定义了 Objective-C对象和对象交互的基本框架。 它将传递给继承自的类和类的实例 它具有作为对象并与运行时协作的能力 系统

不需要从其他类继承任何特殊行为的类 类应成为NSObject类的子类。 类的实例必须至少具有如下行为的能力 运行时使用Objective-C对象。从 NSObject类比重新创建更简单、更可靠 它在一个新的类定义中


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

NSProxy是cocoa提供的另一个根类。NSObject包含isa指针,id不包含。看看什么lol?id是一个isa指针。它在其他编译器中可能与我使用的编译器不同,但据我所知,如果将类型声明为NSObject,编译器将假定该对象实现SomeProtocol的所有方法,甚至是可选方法。@异常如果委托方法是可选的,则由调用方验证对象是否响应选择器。我知道,这就是为什么我说编译器假设它们已实现。如果没有,optionals总是会引起警告,因为编译器无法确定对象是否会在运行时响应。啊,好吧-我第一次读它时误解了你的观点。>>“此对象响应翻译可见的任何选择器”这只是我答案的克隆!对不起:/我在没有答案的时候写的,你把我揍了一顿。。。没有怨恨,也没有必要投反对票。。。另外,您没有提到
NSProxy
…如果它是一个堆栈,并且这个答案在底部,那么@Jasarien首先回答;)@绿柱石:答案的默认显示顺序是按投票总数分类,然后在每一层中随机排列。如果你真的想知道确切的发帖时间,在“X小时前回复”上会有一个工具提示,它会给你时间戳。你也可以点击答案部分顶部的“最旧”标签,按发布日期排列答案。也许七年后不值得一提,但是:回答问题并不是纠正问题中事实错误的正确方法。你应该评论这个问题,甚至重写它。
typedef struct objc_object {
    Class isa;
} *id;