2011-12-09 135 views
5

我有这样的疑问here(以及上的其他quesrtions),以及约Objective-C的集合和快速列举了苹果文档。什么是不明确的,如果填充了不同类型的NSArray和循环就好创建:快速计数

for (NSString *string in myArray) 
    NSLog(@"%@\n", string); 

到底会发生什么吗?循环会跳过什么不是NSString?例如,如果(出于参数的原因)UIView在数组中,当循环遇到该项目时会发生什么?

+3

快速列举“需要你的话。” @awfullyjohn提供了处理具有未知类成员的数组的最佳解决方案。没有隐式的过滤发生,并可能导致调用接收器无法处理的方法...崩溃 –

回答

9

为什么要这么做?我认为这会造成越野车和意外行为。如果阵列中填充了不同的元素,而不是使用:

for (id object in myArray) { 
    // Check what kind of class it is 
    if ([object isKindOfClass:[UIView class]]) { 
     // Do something 
    } 
    else { 
     // Handle accordingly 
    } 
} 

你在做什么在你的例子是有效的一样,

for (id object in myArray) { 
    NSString *string = (NSString *)object; 
    NSLog(@"%@\n", string); 
} 

仅仅因为你投object作为(NSString *)不意思是string实际上将指向NSString对象。以这种方式调用NSLog()将根据NSObject protocol调用- (NSString *)description方法,其中在数组内引用的类可能符合或不符合。如果它符合,它会打印。否则,它会崩溃。

+1

好的一点,但这不能回答这个问题。 – PengOne

+0

问题是对Objective-C的更深入的理解,而不是实际做这样的事情。另外,最近我一直在C#中工作,可以指定进入集合的类型。 –

+1

是的。我会更新我的答案,但基本上,你击败了我。 – john

2

有趣的问题。为快速列举最通用的语法是

for (NSObject *obj in myArray) 
    NSLog(@"%@\n", obj); 

我相信,通过做

for (NSString *string in myArray) 
    NSLog(@"%@\n", string); 

相反,你只是铸造每个对象为NSString。也就是说,我认为上述等同于

for (NSObject *obj in myArray) { 
    NSString *string = obj; 
    NSLog(@"%@\n", string); 
} 

我找不到在苹果的documentation for Fast Enumeration的这种精确提,但你可以检查它的例子,看看会发生什么。

+1

不是“最通用”版本是“for(id obj in arr)”(因为覆盖了(微小的数字)不从'NSObject'下降的对象)? –

2

我只是试过一个简单的例子...这是我的代码。

NSMutableArray *array = [[NSMutableArray alloc] initWithCapacity:1]; 
NSNumber *number = [NSNumber numberWithInteger:6]; 
[array addObject:number]; 
[array addObject:@"Second"]; 

现在,如果我只是登录对象,没有问题。 NSNumber实例正在铸造为NSString,但两种方法都响应-description,所以它不是问题。

for (NSString *string in array) 
{ 
    NSLog(@"%@", string); 
} 

但是,如果我尝试登录NSString-length ...

for (NSString *string in array) 
{ 
    NSLog(@"%i", string.length); 
} 

...它抛出一个NSInvalidArgumentException因为NSNumber不向-length选择作出回应。长话短说,Objective-C给你很多绳索。不要把它挂在上面。

+0

NSNumber不作为NSString被转换。 NSNumber和NSString都是NSObject的后代,NSLog就像你说的那样调用'description'。但没有涉及任何投射。 – 2011-12-09 23:33:47

+0

哦,我明白了。我想我只是混淆了铸造和代码完成功能。在我写这个例子的时候,我没有收到关于'NSNumber'实例的消息'-length'的警告。 –

+0

啊!好的...我现在也明白你的意思了。 NSNumber被作为一个NSString转换为'string'。我以为你是在说NSLog正在做铸造(从提及'description')。我的错! – 2011-12-09 23:56:58

3

你要明白,在OBJ-C的指针没有类型信息。即使您编写NSString*,也只是一个编译检查。在运行期间,一切都只是一个id

Obj-c运行时从不检查对象是否是给定的类。您可以将NSNumbers放入NSString指针中而不会出现问题。只有当您尝试调用未在对象上定义的方法(发送消息)时才会出现错误。

快速枚举如何工作?它完全一样:


for (NSUInteger i = 0; i < myArray.count; i++) { 
    NSString* string = [myArray objectAtIndex:i]; 

    [...] 
} 

这只是因为它在较低的水平上运行更快。

1

由于所有的NSObject对isKindOfClass回应,你仍然可以铸造保持在最低限度:在类

for(NSString *string in myArray) { 
    if (![string isKindOfClass:[NSString class]]) 
     continue; 
    // proceed, knowing you have a valid NSString * 
    // ... 
}