在之前的面试中,面试官问我一个项目中的问题:在可变数组的遍历过程中,删除其中的元素,会发生什么问题?
我们都知道,在数组的遍历过程中,不要删除数组中的元素,会引起crash,可是今天发现并不是所有的循环方式都会造成crash。
下面,我们写一段代码进行测试:
//我们有一个可变数组
NSMutableArray *mArr = [NSMutableArray arrayWithObjects:@1, @2, @3, @4, @5, @6, nil];
// 普通的循环遍历方式
for (NSUInteger i = 0; i < mArr.count; i++) {
[mArr removeObjectAtIndex:i];
}
NSLog(@"%@", mArr);
//打印结果为:2, 4, 6,而且程序没有crash
// 使用迭代器遍历
[mArr enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
[mArr removeObject:obj];
}];
NSLog(@"%@", mArr);
//打印结果为:2, 4, 6,而且程序没有crash
// 使用for-in遍历
for (NSNumber *obj in mArr) {
[mArr removeObject:obj];
}
NSLog(@"%@", mArr);
// 程序crash,
// Terminating app due to uncaught exception 'NSGenericException', reason: '*** Collection <__NSArrayM: 0x6000002588d0> was mutated while being enumerated.'
所以在可变数组的遍历过程中,根据不同的遍历方式,会产生不同的问题。
那么,如果想在遍历过程中,删除数组的元素,该怎么处理呢
大众的做法是新建一个可变数组,把要想保留的元素,加入到新的数组,方法是可行的,有没有更好的解决方案呢?
答案是有的。采用逆序遍历
// 逆序遍历
[mArr enumerateObjectsWithOptions:NSEnumerationReverse usingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
[mArr removeObject:obj];
}];
// 逆序遍历
for (NSNumber *obj in [mArr reverseObjectEnumerator]) {
[mArr removeObject:obj];
}
这样,程序就不会crash,数组中的元素也成功移除了。
补充
在实际开发中,笔者建议要谨慎使用,要多加测试,笔者在使用分割字符串后,初始化一个可变数组进行删除操作就crash了。