当我们可以使用 NSObject 时为什么还要使用 id 呢?
我知道当我们想要创建一个未知值对象时我们使用 id。然而,我很好奇为什么苹果要选择 id 来决定它在运行时的值,当每个对象都是 NSObject 的子类时。因此,我们可以使用 NSObject *delegate
来代替 id delegate
有谁知道为什么吗?谢谢。
I know that when we want to create an unknown value object we use id. However, I'm curious that why did Apple to choose id which decides it's value during runtime, when every object is a subclass of NSObject. So instead of id delegate
we could have used NSObject *delegate
Does anyone know why? Thanks.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
这是不正确的。您可以创建一个从无到有扩展的对象作为根类。
这也许就是引入 id 的原因。
That's not correct. You could make an object that extends from nothing as a root class.
That's perhaps why id was introduced.
id
删除类型,相当于说“这个对象响应任何对翻译可见的选择器”。当然,您有责任在擦除类型时(以及在对它们进行类型转换时)确保您的程序正确。如果类型是
NSObject
,那么如果选择器没有在 NSObject 的接口或其采用的协议中声明,编译器会说“NSObject 可能不会响应选择器”。在这种情况下,您还可以添加类型转换以将其转换为您期望的类型。对于严格/正确的类型,编译器可以介入并帮助您,这很棒,因为 ObjC 是一种非常动态的语言。
id
在使用(或构建)集合类型时特别有用。添加对象不会成为问题,除非您定义了新的根类型(不继承自 NSObject)。如果我们要将其用作基类 (NSObject) 之外的其他内容,则从集合中获取值需要进行类型转换。Objective-C 不支持泛型 - 例如,您不能声明
NSString
的NSArray
。您可以使用NSString
填充NSArray
并通过id
传递它,以便在不保留类型安全时获得更自然的编写风格(类似于泛型) )。那么,让我们用一些实际的代码来扩展它。
示例 A
示例 B
现在假设
id
不可用,我们修复了所有编译器警告,因为这是正确的做法:id
不会在运行时决定其值,任何 NSObject 也不会。 ObjC 对象不执行隐式提升,它们只是在没有正式提升的情况下强制转换指针。与您的示例相关,我实际上将我的委托和参数声明为带有协议的 NSObject:
id
erases the type and it is equivalent to saying "this object responds to any selector visible to the translation". Of course, it is your responsibility to make sure your program is correct when you erase types (and also when you typecast them).If the type were
NSObject
, then the compiler would say "NSObject may not respond to selector" if the selector was not declared in NSObject's interface or the protocols it adopts. In that event, you could also add a typecast to cast it to the type you expect.With strict/correct types, the compiler can kick in and help you out, which is great because ObjC is a very dynamic language.
id
is particularly useful when using (or building) collections types. Adding an object would not be a problem unless you defined a new root type (does not inherit from NSObject). Getting a value from the collection would require a typecast if we were to use it as something other than our base class (NSObject).Objective-C does not support generics - you cannot, for example, declare an
NSArray
ofNSString
s. You can populate anNSArray
withNSString
s and pass this throughid
for a more natural written style when type safety is not preserved (a la generics).So, let's expand on this with some real code.
Example A
Example B
And now let's say
id
is not available and we fix all our compiler warnings because it's the right thing to do:id
doesn't decide its value at runtime, nor does any NSObject. ObjC objects don't perform implicit promotions, they just cast the pointer through without formal promotion.Related to your example, I actually declare my delegates and parameters as NSObjects with protocols:
这是一个不正确的说法。您可以创建不继承自 NSObject 的对象。并不真正推荐,但这是可能的。
NSProxy
就是一个例子 - 它不是从 NSObject 继承的。That is an incorrect statement. You can create objects that do not inherit from NSObject. it's not really recommended, but it is possible.
NSProxy
is an example - it does not inherit from NSObject.以上是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
我认为,这是因为它最初是
C
而不是C++
(或其他更严格的类型语言)。Above is the actual definition of the
id
in Objective-C language. Objective-C runtime system is built aroundid
andClass
. Nothing have to do with NSObject or common super class.http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/ObjectiveC/Chapters/ocObjectsClasses.html#//apple_ref/doc/uid/TP30001163-CH11-SW3
I think, this is because it is originally
C
notC++
(or other more strict typing languages).