该问题来自一道笔试题:
一、执行下面代码会发生什么?什么解决?
NSMutableArray *array = [NSMutableArray arrayWithObjects: @"122", @"333", @"444", nil];
for (NSString *string in array) {
[array removeObject: string];
}
答:会崩溃,提示 NSGenericException 异常。出现下面的报错信息
*** Terminating app due to uncaught exception ‘NSGenericException’, reason: ‘*** Collection <__NSArrayM: 0x600002848ab0> was mutated while being enumerated.’
意思是在枚举时,集合数据被修改了。
原因:
因为for…in…利用了快速枚举 NSFastEnumerate ,其在内部是用 Iterator(迭代器) 实现遍历的,一旦元素变动,之前的元素 全部被失效 ,所以在for each的循环当中,最好不要去进行元素的修改动作,若需要修改,循环改为for遍历,由于内部机制不同,不会产生修改后结果失效的问题。
二、解决办法三种
1、使用普通for循环
NSMutableArray *array = [NSMutableArray arrayWithObjects: @"122", @"333", @"444", nil];
for (int i = 0; i < array.count; i++) {
[array removeObject: array[i]];
}
2、使用copy一个不可变数组进行删除
NSMutableArray *array = [NSMutableArray arrayWithObjects: @"122", @"333", @"444", nil];
NSArray *copyArray = [array copy];
for (NSString *string in copyArray) {
[array removeObject: string];
}
3、使用enumerateObjectsUsingBlock(枚举器)来遍历
NSMutableArray *array = [NSMutableArray arrayWithObjects: @"122", @"333", @"444", nil];
[array enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL * stop) {
[array removeObject: obj];
}];
三、关于NSFastEnumerate迭代器和NSEnumerator枚举器的相关底层文章:
NSFastEnumeration (快速枚举)
Objective-C Fast Enumeration 实现原理
NSEnumerator && NSFastEnumerate