iOS上出现未捕获异常导致应用程序终止

4

我的代码中有一个 for 循环。当执行这个循环时,我的应用程序会崩溃,并在控制台上打印以下消息:

Terminating app due to uncaught exception 'NSRangeException', reason: '-[NSMutableArray objectAtIndex:] index 2 beyond bounds [0 .. 1]'  Call stack at first throw:

使用这个 for 循环,我试图填充一个 NSMutableArray,但实际上并没有完成这个目标。

你能发布出现崩溃的函数吗? - Max
3个回答

14

通常情况下,当您尝试访问超出 NSArray 界限之外的索引处的元素时,就会发生这种情况。

假设您有一个这样的 NSArray

NSArray *a = [NSArray arrayWithObjects:@"a", @"b", @"c", nil];

这段代码会输出 "Array index out of bounds",因为边界是 0 - 2:

@try {
   NSString *string = [a objectAtIndex:3];
} @catch(NSRangeException *e) {
   NSLog(@"Array index out of bounds");
}

解决这个问题最好的方法是使用快速枚举

for(id obj in array) {
   //do something with obj
}

快速枚举使用可枚举对象的NSFastEnumeration协议实现来为您处理所有繁琐的工作。

即使使用快速枚举,通常也会出现一个问题,就是如果您枚举一个可变结构(例如NSMutableArray)并在循环体内使用removeObject:或其变体修改结构,则很快就会遇到此异常,因为结构的长度被缓存,因此即使它越界,它也会继续进行到下一次迭代。

但是,使用快速枚举,您将很快发现此错误,因为内部的__NSFastEnumerationMutationHandler将捕获它并抛出以下异常:

2011-02-11 00:30:49.825 MutableNSFastEnumerationTest[10547:a0f] *** Terminating app due to uncaught exception 'NSGenericException', reason: '*** Collection <NSCFArray: 0x10010c960> was mutated while being enumerated.<CFArray 0x10010c960 [0x7fff70c45ee0]>{type = mutable-small, count = 2, values = (
    0 : <CFString 0x100001078 [0x7fff70c45ee0]>{contents = "b"}
    1 : <CFString 0x100001058 [0x7fff70c45ee0]>{contents = "c"}
)}'
*** Call stack at first throw:
(
    0   CoreFoundation                      0x00007fff8621e7b4 __exceptionPreprocess + 180
    1   libobjc.A.dylib                     0x00007fff80daa0f3 objc_exception_throw + 45
    2   CoreFoundation                      0x00007fff862765bf __NSFastEnumerationMutationHandler + 303
    3   MutableNSFastEnumerationTest        0x0000000100000de7 main + 295
    4   MutableNSFastEnumerationTest        0x0000000100000cb8 start + 52
    5   ???                                 0x0000000000000001 0x0 + 1
)
terminate called after throwing an instance of 'NSException'

1
实际上,你最后一个移除对象的例子会跳过索引,因为你既增加了 i,又将数组向左移动。所以你将删除索引0、2、4等。 - Tim
@TimGostony 哇,好发现!删除了那些不太必要的例子。谢谢! - Jacob Relkin
此外,一个不使用索引枚举和修改数组的好方法是:for(Object *something in [myMutableArr copy]){ /* ... */ [myMutableArr removeObject:something]; } - Tim
当然,这需要复制,但对于大多数使用情况(n <10000),对性能的影响可以忽略不计。同时,不必担心索引计算也更加安全。就应用而言,如果选择是“运行速度快5ns”或“更少崩溃”,我更喜欢后者。 - Tim

1

你的异常提示了你在访问数组时越界了(索引 2 超出范围)。如果你必须访问数组,最好使用快速枚举(for each loop)。

for (NSString *str in array)
    NSLog(@"%@", str);

像这样的代码可以防止任何索引越界异常。


1

这种异常类型被称为数组越界异常。通常发生在尝试访问不存在的数组元素时。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接