5

我在这里有这个问题(以及关于 SO 的其他问题),以及关于 Objective-C 集合和快速枚举的 Apple 文档。尚不清楚的是是否NSArray填充了不同的类型,并且创建了一个循环,如下所示:

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

这里到底发生了什么?循环是否会跳过任何不是NSString? 例如,如果(为了参数)aUIView在数组中,当循环遇到该项目时会发生什么?

4

5 回答 5

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 协议调用方法- (NSString *)description数组中引用的类可能符合也可能不符合。如果符合,它将打印出来。否则,它会崩溃。

于 2011-12-09T22:37:30.680 回答
3

You have to understand that a pointer in obj-c has no type information. Even if you write NSString*, it's only a compilation check. During runtime, everything is just an id.

Obj-c runtime never checks whether objects are of the given class. You can put NSNumbers into NSString pointers without problems. An error appears only when you try to call a method (send a message) which is not defined on the object.

How does fast enumeration work? It's exactly the same as:


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

    [...]
}

It's just faster because it operates on lower level.

于 2011-12-09T23:04:38.960 回答
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 );
}

我在 Apple 的Fast Enumeration 文档中找不到对此的准确提及,但您可以通过示例查看它,看看会发生什么。

于 2011-12-09T22:36:18.240 回答
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);
}

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

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

...它抛出一个NSInvalidArgumentException因为NSNumber不响应-length选择器。长话短说,Objective-C 给了你很多东西。不要用它来吊死自己。

于 2011-12-09T22:46:49.833 回答
1

由于所有 NSObject 都响应 isKindOfClass,您仍然可以将转换保持在最低限度:

for(NSString *string in myArray) {
    if (![string isKindOfClass:[NSString class]])
        continue;
    // proceed, knowing you have a valid NSString *
    // ...
}
于 2013-01-31T07:17:22.993 回答