4

我有两个功能:

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

- (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:

集合 <__NSOrderedSetArrayProxy: 0x123456> 在被枚举时发生了变异

到底是什么东西变异了。我不明白。从该数组返回一个副本可以解决问题,但我仍然不明白。

该错误与 NSMutableOrderedSet 有关系,如果我用数组替换该集合,则不会出现异常。

一些截图,抛出异常

所有异常断点 碰撞

4

2 回答 2

3

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

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

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

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

这应该可以解决快速枚举/变异问题。请注意,我完全不知道为什么要在 obj 等于 42 时将枚举数移到一个步骤上,但我假设在整个代码库的上下文中这是有道理的!

于 2013-07-29T20:21:02.890 回答
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.只需做一个copyNSArray 并使用它

- (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!
        }
    }
}
于 2013-07-30T05:46:31.577 回答