遍歷數(shù)組的同時刪除元素引起崩潰的問題
一躲履、問題
使用 for in
遍歷可變數(shù)組的同時刪除元素會造成崩潰
崩潰日志為:
2018-03-10 19:40:43.970096+0800 ArrayRemoveObj[6500:611281] *** Terminating app due to uncaught exception 'NSGenericException', reason: '*** Collection <__NSArrayM: 0x60400005a9a0> was mutated while being enumerated.'
*** First throw call stack:
(
0 CoreFoundation 0x0000000103cc012b __exceptionPreprocess + 171
1 libobjc.A.dylib 0x0000000103354f41 objc_exception_throw + 48
2 CoreFoundation 0x0000000103d33b0c __NSFastEnumerationMutationHandler + 124
3 ArrayRemoveObj 0x0000000102a476a2 main + 834
4 libdyld.dylib 0x00000001076e8d81 start + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException
所以 遍歷可變數(shù)組
時,最好不要做刪除數(shù)組中元素的操作敦腔,因為刪除操作可能會引起數(shù)組容量的變化,導致數(shù)組越界等問題。
二同廉、分析
結(jié)合網(wǎng)上資料及實際代碼對for in
, enumerateObjectsUsingBlock:
,for
進行實際的分析。
聲明如下數(shù)組:
NSMutableArray *array = [NSMutableArray arrayWithArray:@[@"aaa",@"bbb",@"ccc",@"ddd",@"eee"]];
使用 for in
必崩:
for (NSString *obj in array) {
if ([obj isEqualToString:@"ddd"]) {
[array removeObject:obj];
}
}
使用 enumerateObjectsUsingBlock:
未崩潰
[array enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
if ([obj isEqualToString:@"ddd"]) {
[array removeObject:obj];
}
}];
使用 for
未崩潰
for (int i = 0; i < array.count; i++) {
NSString *obj = array[i];
if ([obj isEqualToString:@"ddd"]) {
[array removeObject:obj];
}
}
記得會造成崩潰柑司,有可能會造成數(shù)組越界迫肖。據(jù)說可能是蘋果對此進行了保護,不推薦此法帜羊。
三咒程、結(jié)論
從上面來看只for in
會造成崩潰,但是結(jié)合以往經(jīng)驗來看最穩(wěn)妥的方案讼育,是對數(shù)組逆序遍歷帐姻,然后再刪除元素就沒有問題了。
使用for in
的逆序遍歷刪除元素:
for (NSString *obj in array.reverseObjectEnumerator) {
if ([obj isEqualToString:@"ddd"]) {
[array removeObject:obj];
}
}
使用enumerateObjectsWithOptions:
逆序遍歷刪除元素:
[array enumerateObjectsWithOptions:NSEnumerationReverse usingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
if ([obj isEqualToString:@"ddd"]) {
[array removeObject:obj];
}
}];
使用for
逆序遍歷刪除元素:
for (int i = array.count - 1; i >= 0; i--) {
NSString *obj = array[i];
if ([obj isEqualToString:@"ddd"]) {
[array removeObject:obj];
}
}
最后提供一種容易理解的方法:把需要刪除的元素放入新的數(shù)組中奶段,遍歷完成后饥瓷,統(tǒng)一刪除。這種在大量元素操作的時候痹籍,效率低下呢铆,推薦使用逆序遍歷方式。
NSMutableArray *tempArray = nil;
for (NSString *obj in array) {
if ([obj isEqualToString:@"ddd"]) {
if (tempArray == nil) {
tempArray = [NSMutableArray array];
}
[tempArray addObject:obj];
}
}
if (tempArray && tempArray.count>0) {
[array removeObjectsInArray:tempArray];
}