2013-03-11 80 views
0

我有一個NSMutableArrayUIImageViews,我連續遍歷(使用CADisplayLink)。我這樣做是爲了不斷移動屏幕上的UIImageViews當使用某些類型的方法刪除對象時出現NSMutableArray錯誤

當我從陣列中刪除UIImageView,我有時會收到錯誤:

EXC_BAD_ACCESS (code=1, address=0x20000008) 

但是我用得到的錯誤「陣列,同時列舉突變」過去之前,我開始使用ARC/iOS6,所以我認爲這兩個錯誤意味着完全相同的事情,但我不知道。

無論如何,這裏是我的問題。使用以下任何方法從陣列中刪除UIImageView會導致上述錯誤。

[imageViews removeObject:imageView];

[imageViews performSelector:@selector(removeObject:) withObject:imageView];

[imageViews performSelectorOnMainThread:@selector(removeObject:) withObject:imageView waitUntilDone:YES];

然而,使用任何低於方法從未給我的錯誤。

[imageViews performSelectorOnMainThread:@selector(removeObject:) withObject:imageView waitUntilDone:NO];

[imageViews performSelector:@selector(removeObject:) withObject:imageView afterDelay:.01];

這樣可以爲什麼刪除使用第一組的上面列出的方法從NSMutableArray對象有人向我解釋給我什麼,我相信這是一個「陣列,同時列舉突變」錯誤,而使用第二組方法不會給我那個錯誤?

我一直在使用上面列出的第二組方法來解決這個錯誤(並且如果我使用它們,一切都可以正常工作),但我想知道爲什麼當我使用它們時我的問題得到了解決,如果使用這兩種方法中的一種是安全的。

這是我第一次發佈一個問題,所以原諒我,如果我發佈這個錯誤的方式。

回答

2

由於CADisplayLink在後臺線程上回調,完全可能的是,通過調度有問題的數組以從給定線程中移除給定對象,另一個正在修改或枚舉拋出異常的數組。前兩種方法不起作用,因爲它們需要對數組進行同步訪問(NSMutableArray沒有提供),它們在當前線程的運行循環中調度,而不是主線程,因此它們各自的執行不能保證不能同時訪問相同的資源。底部的兩個工作是因爲,假設你在主線程上改變數組,那麼運行循環不可能安排枚舉指令和同時改變指令(一個線程不能在同時,特別是在運行循環的下一次迭代中計劃該代碼時),因此該數組訪問更安全。通過使用延遲,你創造了一個競賽條件,這對你來說迄今爲止工作過,但會在以後再次出現。

+0

所以你會建議堅持執行performSelectorOnMainThread方法,如果它工作,或者我應該做什麼@Alastair陳述只是爲了安全(雖然它可能會增加我的項目的開銷)。此外,爲什麼你認爲當waitUntilDone設置爲NO我沒有得到錯誤,但如果它被設置爲YES,我會得到錯誤?謝謝。 – 2013-03-11 23:30:54

+1

@gfrs開銷太小,不值得優化。至於獲得錯誤,通過YES實際上更安全,您的測試只是揭示了您必須解決的另一個競爭條件。 – CodaFi 2013-03-12 02:52:58

1

當你枚舉一個數組(通過for ... in ...循環或使用NSEnumerator來遍歷它)時,枚舉要求在循環本身或其他線程中不要同時更改數組(因此原來的警告)。

我不知道爲什麼底部的兩個方法的工作 - 我會在內部猜測他們改變數組的方式,不影響枚舉。儘管如此,這是不好的做法,我不會建議以任何方式在列舉期間更改數組。即使它今天有效,它可能不是明天。我會建議存儲的索引要刪除,直到枚舉後,然後刪除它們在this answer

相關問題