对NSMutableArray问题的快速枚举

时间:2015-06-19 00:42:17

标签: objective-c nsmutablearray enumeration

我有一些问题试图解决为什么我们不能在枚举期间改变集合...显然,如果你正在进行任何类型的快速枚举,系统应该抛出异常,如果你试图变异。下面我有三个例子,我在枚举期间进行变异。一个是简单的C风格循环,另外两个使用某种形式的快速枚举。我只得到案例2抛出的枚举异常。难道我也没有为案例1抛出异常吗?案例1为何有效?此外,整个堆栈溢出的人说我的案例3是不好的做法,但为什么呢?这很简单,似乎很有效。两个不同的快速枚举循环如何表现的不一致以及对C风格循环的普遍厌恶与我的理解相吻合。如果某人真的可以将其分解为科学,那么这将是真正有用的,而不是模糊的通用经验法则。从基本层面来说,我想知道为什么例外在这里不一致,以及为什么案例3对我来说很明显"不应该"#34;或者是不良做法。"

//Case 1:
NSMutableArray *array = [NSMutableArray arrayWithObjects:@"phuj", @"whub", @"adgh", nil];
[array enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
        [array removeObjectAtIndex:idx];
}];

//Case 2:
NSMutableArray *array = [NSMutableArray arrayWithObjects:@"phuj", @"whub", @"adgh", nil];
for (NSString *string in array) {
    [array removeObject:string];
}

//Case 3:
NSMutableArray *array = [NSMutableArray arrayWithObjects:@"phuj", @"whub", @"adgh", nil];
for (int i = 0; i < [array count]; i++) {
    [array removeObjectAtIndex:i];
}

1 个答案:

答案 0 :(得分:0)

我们喜欢简单直接的代码。

我不会谈论案例2,因为它会引发异常并且您无法改变其中的数组。

我想从一个例子开始,假设我们要删除&#34; whub&#34;来自一个可变数组的项目,数组的内容是&#34; phuj,whub,whub,adgh&#34;,你看到它有两个whub。

让我们开始使用c style loop编写代码:

for (int i = 0; i < [mArray1 count]; i++) {
    NSString *str = mArray1[i] ;
    if ([str isEqualToString:@"whub"]) {
        [mArray1 removeObjectAtIndex:i] ;
    }
}

代码有一个错误,在删除第一个&#34; whub&#34;之后,位于其后面的项目的所有索引将减少1,因此第二个whub的索引应为1并且{{1}此刻是1。在下一个循环中,i为2,因此它会跳过第二个whub。您可以更改代码以使其正确。

i

它有效,但它并不简单,我们修改了索引for (int i = 0; i < [mArray1 count]; i++) { NSString *str = mArray1[i] ; if ([str isEqualToString:@"whub"]) { [mArray1 removeObjectAtIndex:i] ; --i ; } } ,它使代码变得复杂。

让我们尝试使用i方法编写代码,例如案例1:

enumerateObjectsUsingBlock

如果你构建并运行它,你会发现结果数组仍然包含一个&#34; whub&#34;而这一次,我们无法修改索引来修复它。

结论:你说的很多,你可以在循环中改变数组,你可以改变数组的事实并不意味着你会得到正确的答案。事实上,使用c风格循环你可以做任何你想做的事情,它不会崩溃,但我们说它很糟糕,因为我们有更好的方法。在实践中,我们希望使用简单的代码来实现目标,因此其他人可以轻松理解,我们自己也可以从中受益。

我想用这种方式,我认为这很简单直接。

NSMutableArray *array = [NSMutableArray arrayWithObjects:@"phuj", @"whub", @"whub", @"adgh", nil] ;
[array enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
    if ([obj isEqualToString:@"whub"]) {
        [array removeObjectAtIndex:idx] ;
    }
}];