2013-07-25 46 views
4

「NSOrderedSetArrayProxy物而被枚舉突變的」我有兩個功能:得到一個誤差無突變

一個返回填充在一個塊

- (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,如果我更換一個數組我沒有得到一個異常。

一些截圖,拋出的異常

all exceptions breakpoint crash

+0

什麼是你想達到與循環或與該行? –

+0

哪一個?這只是簡化代碼。 – peko

+0

導致錯誤的那個。你爲什麼想要推進統計員? –

回答

3

您正在使用快速列舉而改變一個枚舉實例。

基本上它是一個很大的禁忌,修改您快速枚舉的對象(您使用的for循環的形式使用快速枚舉)。但是,您使用[enumerator nextObject];訪問枚舉器中的下一個對象,但此通過從中刪除當前對象來修改枚舉器。因此,您可以在 a 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時將枚舉器移動一步,但我認爲在整個代碼庫的上下文中這是有道理的!

+0

你能否解釋一下爲什麼在getArray函數中返回數組副本可以修復這個問題? – peko

+0

除了在同一個循環中混合並匹配NSEnumerator和快速枚舉之外,你不知道Apple如何在底層實現它們。有關更詳細的討論,請參閱[this](http://developer.apple.com/library/ios/#DOCUMENTATION/Cocoa/Conceptual/Collections/Articles/Enumerators.html)。 –

+0

而且這可能是合適的:「在枚舉可變集合的元素時,刪除,替換或添加可變集合的元素並不安全。如果您需要在枚舉期間修改集合,則可以創建集合的副本並使用副本枚舉或在枚舉過程中收集所需信息,然後應用更改。 –

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! 
     } 
    } 
}