我知道,当我们想要创建一个未知值的对象时,我们会使用id.然而,我很好奇,当每个对象都是NSObject的子类时,为什么苹果会 Select 在运行时决定其值的id.所以我们可以用NSObject *delegate
而不是id delegate
,有人知道为什么吗?谢谢
我知道,当我们想要创建一个未知值的对象时,我们会使用id.然而,我很好奇,当每个对象都是NSObject的子类时,为什么苹果会 Select 在运行时决定其值的id.所以我们可以用NSObject *delegate
而不是id delegate
,有人知道为什么吗?谢谢
id
删除类型,这相当于说"此对象响应翻译可见的任何 Select 器".当然,当你删除类型时(以及当你打字时),确保你的程序是正确的是your的责任.
如果类型为NSObject
,那么如果 Select 器未在NSObject的接口或其采用的协议中声明,编译器会说"NSObject可能不响应selector".在这种情况下,您还可以添加一个类型转换,将其转换为您期望的类型.
对于严格/正确的类型,编译器可以启动并帮助您完成,这很好,因为ObjC是一种非常动态的语言.
id
在使用(或构建)集合类型时特别有用.除非定义了新的根类型(不从NSObject继承),否则添加对象不会有问题.如果我们要将其用作基类(NSObject)以外的东西,则从集合中获取值需要类型转换.
Objective-C不支持泛型——例如,您不能声明NSString
s中的NSArray
个.在没有保留类型安全性的情况下(a la泛型),可以用NSString
填充NSArray
,并将其传递到id
,以获得更自然的书写风格.
所以,让我们用一些真实的代码来扩展一下.
Example A
NSString * string = [array objectAtIndex:0]; // << trust me (via id)
return [string length];
-or-
return [[array objectAtIndex:0] length]; // << trust me (via id)
Example 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对象不执行隐式提升,它们只是在没有正式提升的情况下投射指针.
与您的示例相关,我实际上将我的委托和参数声明为具有协议的NSObject:
NSObject<MONShapeDelegate>* delegate;