從堆棧跟蹤我只能看出這是一個競爭條件,更具體在strong
屬性或可變數據的比賽,很可能在一本字典。由於崩潰發生在主線程上,我的第一個猜測是你在背景線程上使用了API,而後臺線程不應該訪問它。
- 爲什麼我認爲這是一場數據競賽?
- 由於競爭條件,核心數據代碼在主線程上崩潰的最可能原因是什麼?
- 修復此錯誤的一些建議。
爲什麼我認爲這是一個數據的比賽?
由於墜毀objc_retain
發生。這只是經驗。在我看到保留一個對象發生崩潰的10個案例中,有9個是因爲數據競賽。在另外一種情況下,罪魁禍首是手動進行內存管理錯誤。如果您對更多細節感興趣,可以查看objc_storeStrong()的來源。
其次,Concurrency section in the Core Data Reference有這個有趣的信息:
NSMainQueueConcurrencyType是專門爲您的應用程序接口的使用,並且只能在應用程序的主隊列中。
的NSPrivateQueueConcurrencyType配置在初始化時創建自己的隊列,並可以在該隊列中僅使用。由於隊列是NSManagedObjectContext實例的私有和內部隊列,因此只能通過performBlock:和performBlockAndWait:方法訪問該隊列。
由於競爭條件,核心數據代碼在主線程上崩潰的最可能原因是什麼?
根據您問題中的代碼,您正在使用NSMainQueueConcurrencyType
,因此核心數據不應該在具有此「託管上下文」的背景隊列上使用。
我的猜測是你正在從某個背景線程調用核心數據API。
固定這個錯誤有幾個建議。
競爭情況並不總是導致崩潰。出於這個原因,這種崩潰有時不容易被重現。然而,所有的東西都不會丟失。
要查看它是否確實是數據競賽,您必須查看完整的崩潰報告。通過崩潰報告,您不僅可以追蹤崩潰的主線程,還可以在崩潰發生時追蹤進程的所有其他線程。 (只需在崩潰報告中搜索「CoreData」)。如果您非常不走運,在任何後臺線程上都不會顯示核心數據API。在這種情況下,你至少應該看到一個有一些「autorelasepoolpop」框架的線程。如果您在後臺堆棧跟蹤中發現了一些「CoreData」幀,請在該堆棧跟蹤中找到指向您的應用代碼的幀。你有罪魁禍首。
爲了進行調試,您可以在任何地方調用幾個assert([NSThread isMainThread]);
調用,無論您調用核心數據API。如果因斷言失敗而崩潰,則知道問題出在哪裏。
如果您使用的是Xcode 9,您可能需要嘗試新的「主線程清理程序」(在「診斷程序」下的方案設置中,在同一個面板中還配置了「線程清理程序」。想「暫停問題」)。如果這不起作用,請嘗試使用「線程清潔劑」。
您也可以將併發類型切換爲NSPrivateQueueConcurrencyType
。請確保將所有核心數據API調用與performBlock:
和performBlockAndWait:
調用包裝在一起,否則您將不會獲得更少的崩潰,但會導致更多的崩潰。如果您確實需要使用來自後臺隊列的核心數據,則可以採用這種方式。出於性能原因。
如果幸運的話,這只是一個小小的代碼錯誤,可以在10分鐘內修復:-)。如果你非常不走運,應用程序的併發架構就會崩潰,你必須(重新)設計它: - /。
希望這會有所幫助。
看起來像數據競賽.. – Michael