id 删除类型,相当于说“此对象响应任何对翻译可见的选择器”。当然,您有责任确保您的程序在擦除类型时(以及在类型转换时)是正确的。
如果类型是NSObject,那么如果选择器没有在 NSObject 的接口或它采用的协议中声明,编译器会说“NSObject 可能无法响应 selector”。在这种情况下,您还可以添加一个类型转换以将其转换为您期望的类型。
使用严格/正确的类型,编译器可以启动并帮助您,这很棒,因为 ObjC 是一种非常动态的语言。
id 在使用(或构建)集合类型时特别有用。除非您定义了新的根类型(不继承自 NSObject),否则添加对象不会有问题。如果我们要将集合用作基类 (NSObject) 以外的东西,则从集合中获取值需要进行类型转换。
Objective-C 不支持泛型 - 例如,您不能声明 NSArray 或 NSStrings。您可以使用NSStrings 填充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;