得到“NSOrderedSetArrayProxy被枚举时被突变”错误没有变异

时间:2013-07-25 08:12:14

标签: ios objective-c exception block enumeration

我有两个功能:

返回一个填充在块中的数组

- (NSArray *)getArray {
    NSArray *someValues = @[@0, @42, @23, @5, @8, @2013];
    NSArray *filter = @[@42, @23, @5];

    //replacing this NSMutableOrderedSet with a NSMutableArray
    //and return just matched then, resolves the problem.
    //so the exception has to do something with that set.
    NSMutableOrderedSet *matched = [[NSMutableOrderedSet alloc] init];

    for (id value in someValues) {
        [filter enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
            if ([obj isEqual:value])
                [matched addObject:value];
        }];
    }
    return [matched array];
}

和另一个从第一个方法

枚举返回的数组
- (void)enumArray:(NSArray *)array {
    NSEnumerator *enumerator = [array objectEnumerator];
    for (id obj in enumerator) {
        if ([obj isEqual:@42])
            [enumerator nextObject]; // <== this line causes the error!
    }
}

如果我现在做那样的话

NSArray *array = [foo getArray];
[foo enumArray:array];

我将收到一条带有以下消息的NSGenericException:

  

Collection&lt; __ NSOrderedSetArrayProxy:0x123456&gt;在变异的同时   被列举

地狱是变异的地方。我不懂。从该数组返回一个副本解决了问题,但我仍然没有得到它。

错误已经对NSMutableOrderedSet做了一些事情,如果我用数组替换该集合,我不会得到异常。

一些异常抛出的截图

all exceptions breakpoint crash

2 个答案:

答案 0 :(得分:3)

在更改枚举器实例时,您正在使用快速枚举

基本上,修改一个你快速枚举的对象是一个很大的禁忌(你正在使用的for循环形式使用快速枚举)。但是,您使用[enumerator nextObject];从枚举器访问下一个对象,但此通过从中删除当前对象来修改枚举器。所以你在一个for...in循环中使用nextObject 来改变枚举器。

使用while循环而不是for循环快速解决这个问题,有点像这样:

- (void)enumArray:(NSArray *)array {
    NSEnumerator *enumerator = [array objectEnumerator];
    while ((id obj = [enumerator nextObject])) {
        if ([obj isEqual:@42])
            [enumerator nextObject]; 
    }
}

这应该超过快速枚举/突变问题。注意,我完全不知道为什么你想在obj等于42的步骤中移动枚举器,但是假设在整个代码库的上下文中这是有意义的!

答案 1 :(得分:0)

基本原因是,在您通过它时,您无法编辑/修改可变数组。

所以这是两个解决方案,

1.请在变异时使用 @synchronized() 指令锁定数组。

- (void)enumArray:(NSArray *)array {

    NSEnumerator *enumerator = [array objectEnumerator];
    for (id obj in enumerator)
    {
        if ([obj isEqual:@42])
        {
            @synchronized(enumerator)
            {
              [enumerator nextObject]; // <== this line causes the error!
            }
        }
    }
}

2.你只需要 copy NSArray并使用它

- (void)enumArray:(NSArray *)array {

    NSEnumerator *enumerator = [[array copy] objectEnumerator];

    for (id obj in enumerator)
    {
        if ([obj isEqual:@42])
        {
          [enumerator nextObject]; // <== this line causes the error!
        }
    }
}