最近在用 Swift 寫自己的新項(xiàng)目 Fontzar, 擼了個(gè)遍歷時(shí)移除不符合條件的值的碼然后 build and run, 崩了遇伞!沒錯(cuò)是崩了!報(bào)了個(gè)Fatal error: Index out of range
var arr = ["a","c","a"]
for (idx, value) in arr.enumerated() {
if value == "a" {
arr.remove(at: idx)
}
}
print(arr)
同樣代碼用 OC 寫不會(huì)蹦!祈纯?!
NSMutableArray *arr = @[@"a",@"c",@"a"].mutableCopy;
[arr enumerateObjectsUsingBlock:^(NSString* str, NSUInteger idx, BOOL * _Nonnull stop) {
if ([str isEqualToString:@"a"]) {
[arr removeObjectAtIndex:idx];
}
}];
NSLog(@"%@", tempMArr);
我覺得在 Swift 中崩潰是因?yàn)?Swift 是安全的,讓我們提前發(fā)現(xiàn)了問題拖吼。
Swift的特點(diǎn): 快速 現(xiàn)代 安全 互動(dòng)
注意:
遍歷中不能直接操控原數(shù)組,因?yàn)檫@會(huì)改變數(shù)組長度導(dǎo)然后導(dǎo)致隱藏Bug
,你檢查錯(cuò)誤都不知哪出問題了(請(qǐng)看下面的代碼)腺劣。
NSMutableArray *tempMArr = @[@"a",@"x",@"d",@"c",@"a",@"j",@"a",@"c",@"a",@"k",@"f"].mutableCopy;
NSArray *tempArr = @[@"a",@"b",@"c"];
[tempMArr enumerateObjectsUsingBlock:^(NSString* str, NSUInteger idx, BOOL * _Nonnull stop) {
BOOL isExisted = NO;
for (NSString *str2 in tempArr) {
if ([str isEqualToString:str2]) {
isExisted = YES;
break;
}
}
if (!isExisted) {
[tempMArr removeObjectAtIndex:idx];
}
}];
NSLog(@"tempMArr:%@", tempMArr);
控制臺(tái)打印出的結(jié)果:
tempMArr:(
a,
d,
c,
a,
a,
c,
a,
f
)
從打印出來的結(jié)果我們發(fā)現(xiàn)數(shù)組中多了 f
和 d
绿贞,這結(jié)果是不符合我們預(yù)期。從而證明了遍歷中不能操作原數(shù)組的真理橘原!
正確姿勢(shì):
- 遍歷中把符合條件的值保存在新的數(shù)組里
- 遍歷拷貝的數(shù)組籍铁,操作原數(shù)組
- 倒序遍歷數(shù)組
- 使用 Filter 函數(shù)
filter(_:)
OrfilteredArrayUsingPredicate:
PS: 如果你用 Swift 開發(fā)時(shí)遇到了這個(gè)問題涡上,可能是因?yàn)槟阌?OC 時(shí)這么玩過,或者是你曾經(jīng)所看過的《iOS 中如何遍歷數(shù)組拒名?》系列的 Blog 本身就有問題吩愧,誤導(dǎo)你了或沒提醒你。提醒一下
除了 OC 以外的編程語言中就算允許你遍歷中操作原數(shù)組(不崩潰)也全力避免這種騷操作增显。最后記得審一下你的 OC 代碼 ??