Objective c 不同类型NSArray的快速枚举
我有这个问题(以及其他问题),还有关于Objective-C集合和快速枚举的Apple文档。不清楚的是,如果一个Objective c 不同类型NSArray的快速枚举,objective-c,fast-enumeration,Objective C,Fast Enumeration,我有这个问题(以及其他问题),还有关于Objective-C集合和快速枚举的Apple文档。不清楚的是,如果一个NSArray填充了不同的类型,并且创建了如下循环: for ( NSString *string in myArray ) NSLog( @"%@\n", string ); 这里到底发生了什么?循环是否会跳过任何不是NSString的内容?例如,如果(为了论证)数组中有一个UIView,当循环遇到该项时会发生什么情况?有趣的问题。快速枚举最通用的语法是 for ( NSO
NSArray
填充了不同的类型,并且创建了如下循环:
for ( NSString *string in myArray )
NSLog( @"%@\n", string );
这里到底发生了什么?循环是否会跳过任何不是
NSString
的内容?例如,如果(为了论证)数组中有一个UIView
,当循环遇到该项时会发生什么情况?有趣的问题。快速枚举最通用的语法是
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 );
}
我在苹果的文章中找不到对这一点的确切提及,但你可以在一个例子中查看一下,看看会发生什么。你为什么要这样做?我认为这会导致错误和意外行为。如果阵列中填充了不同的元素,请改用以下方法:
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);
}
仅仅因为您将
对象
强制转换为(NSString*)
,并不意味着字符串
实际上将指向一个NSString
对象。以这种方式调用NSLog()
将根据调用-(NSString*)description
方法,数组中引用的类可能符合,也可能不符合。如果符合,它会打印出来。否则,它将崩溃。我刚刚尝试了一个快速示例。。。这是我的密码
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给了你很大的束缚。不要自责。您必须了解obj-c中的指针没有类型信息。即使您编写NSString*
,这也只是一个编译检查。在运行时,一切都只是一个id
Obj-c运行时从不检查对象是否属于给定类。您可以毫无问题地将NSNumbers放入NSString指针。只有在尝试调用对象上未定义的方法(发送消息)时,才会出现错误
快速枚举是如何工作的?这与:
for (NSUInteger i = 0; i < myArray.count; i++) {
NSString* string = [myArray objectAtIndex:i];
[...]
}
对于(整数i=0;i
因为它在较低的级别上运行,所以速度更快。因为所有NSObject对类的响应都是类的,所以您仍然可以将强制转换保持在最低限度:
for(NSString *string in myArray) {
if (![string isKindOfClass:[NSString class]])
continue;
// proceed, knowing you have a valid NSString *
// ...
}
问题更多的是对Objective-C的深入理解,而不是实际做这样的事情。另外,我最近一直在使用C#,在这里可以指定进入集合的类型。True。我会更新我的答案,但基本上,你比我快。对你的帖子有一点澄清:
NSObject
本身符合NSObject
协议,因此任何继承自NSObject
类的对象(即,除了消失的少数之外)也符合协议。@JoshCaswell很好看。我只是想更深入地解释引擎盖下面发生了什么,并举一个可能是有车的、意外行为的例子。也许这个特定实例不是最常见的问题,但最好记住实际调用的是什么,以避免潜在的崩溃,因为即使是像NSLog()
这样看似无辜的调用也不会总是适用于非类型化或错误类型的对象。快速枚举对类“言而有信”@John提供了处理具有未知类成员的数组的最佳解决方案。没有发生隐式筛选,可能导致调用接收方无法处理的方法。。。Crashnsumber不是作为NSString铸造的。NSNumber和NSString都是NSObject的后代,正如您所说,NSLog调用了其中的description
。但这不涉及演员阵容。哦,我明白了。我想我只是把强制转换和代码完成特性混淆了。在编写示例时,我没有收到关于NSNumber
实例上的消息-length
的警告。啊!好的…我现在也明白你的意思了。正在将NSNumber作为NSString转换为字符串
。我还以为你是说NSLog在做演员(从提到description
开始)。我的错!对于(arr中的id obj)(因为它涵盖了(极少数)不从NSObject
下降的对象)来说,“最通用”的版本不是吗?