ID没有警告?

问题描述:

我刚刚发现了一些令我有点困惑的东西,不知有人会为我澄清这件事。ID没有警告?

NSArray *nextArray = [NSArray arrayWithObjects:@"ONE", @"TWO", @"THREE", nil]; 
for(id eachObject in nextArray) { 
    NSLog(@"COUNT: %d", [eachObject length]); 
} 

为什么上述内容不会抱怨/警告我正在询问身份证的长度这一事实?

+0

因为(id)可能是任何NSObject。就像一个可以有长度的NSString。 – Popeye 2012-08-01 16:53:23

+1

@Popeye:甚至不需要是NSObject。可以继承NSProxy,或者一些完全不同的基类。尽管在实践中,几乎所有东西都至少符合NSObject协议。 – 2012-08-01 16:59:15

+0

我看到了,我知道id可以是任何Objective-C类,但我一直认为你必须在尝试访问它之前检查类型并进行投射。非常感激。 – fuzzygoat 2012-08-01 17:00:20

当您不需要编译器类型检查时,您可以使用id。您可以发送任何消息到id类型而不发出警告,并且您可以将id分配给任何其他类型,而不进行类型转换。

这允许您从数组中取出一个对象而不使用转换。例如,你可以自由地假设数组包含NSString的:

NSString* someString = [myArray objectAtIndex:1]; 

它也可以让你将消息发送到一个对象而浇注或者警告。实际上,您希望发送的消息可能不是任何正式类别或协议的一部分:

id someObject = [myArray objectAtIndex:1]; 
if ([someObject respondsToSelector:@selector(setName:)]) 
{ 
    [someObject setName:@"Foo"]; 
} 

编译器永远不会输入发送给ID的检查消息。这部分是Objective-C的活力所在。

如果eachObject是任何其他类型,那么如果编译器无法解析方法名称,则会发生错误。

Objective-C中的每个对象都知道它有什么类,它是否可以处理消息。编译器不是检查类,它是运行时的对象本身。

对象的类可以在compilertime时未定义,但是在运行时每个对象都有一个定义的类。

简单地说,id表示所有的Objective-C类。所以,它的长度方法它属于一个NSString类。编译器不会向您发出警告。 id在运行时动态确定,在编译时未知。

In Objective-C id是任何类型对象的普通类型,不管类是什么类型的,都可以用于类的实例和类对象本身。 id类型完全是非限制性它没有关于对象的信息,除了它是一个对象。所以编译器无法知道该对象是否可以响应某个方法,因为它不知道它是什么类型的对象。 通过在你的代码中使用它,你基本上会说'不管这是指向什么,执行这个操作'。

NSArray可能包含不同的对象类型,例如:

NSArray *thArray = [[NSArray alloc] initWithObjects:@"Stack",@"Overflow",[NSNumber numberWithInt:10],nil]; 
for(id theObject in thArray) { 
    NSLog(@"COUNT: %lu", [theObject length]); 
} 

id可以表示任何对象(在此情况下NSStringNSNumber),
为此编译器不能知道原始的方法length是否存在。

+0

优秀的答案,但你可能想纠正一件小事:'长度'不是一个属性。 – jlehr 2012-08-01 17:01:00

+0

哎呀,愚蠢的错误,用'原始方法'取代'property'。谢谢:) – Anne 2012-08-01 17:03:57

+1

谢谢,它可能值得添加如果([theObjectresponseToSelector:@selector(length)]){...以防万一有人认为代码将在运行时工作。 – fuzzygoat 2012-08-01 17:25:16