[英]Core Data concurrency issue and how to fix
我在Core Data
應用程序中使用了多個上下文,並且最近發生了一些核心數據並發崩潰。 我添加了-com.apple.CoreData.ConcurrencyDebug 1
來幫助跟蹤這些問題,但是我不了解如何解決所顯示的問題。
這是我在做什么:
- (void)getEvents:(void (^)(NSArray *fetchedItems))completionBlock {
// Initialize Fetch Request
NSFetchRequest *request = [[NSFetchRequest alloc] initWithEntityName:@"ZSSCDEvent"];
// Initialize Asynchronous Fetch Request
NSAsynchronousFetchRequest *asynchronousFetchRequest = [[NSAsynchronousFetchRequest alloc] initWithFetchRequest:request completionBlock:^(NSAsynchronousFetchResult *result) {
dispatch_async(dispatch_get_main_queue(), ^{
// Dismiss Progress HUD
[SVProgressHUD dismiss];
// Process Asynchronous Fetch Result
if (result.finalResult) {
NSArray *results = result.finalResult;
completionBlock(results);
// Reload Table View
[self.activityIndicator stopAnimating];
[self.tableViewList reloadData];
}
});
}];
// Execute Asynchronous Fetch Request
[self.managedObjectContext performBlock:^{
// Execute Asynchronous Fetch Request
NSError *asynchronousFetchRequestError = nil;
NSAsynchronousFetchResult *asynchronousFetchResult = (NSAsynchronousFetchResult *)[self.managedObjectContext executeRequest:asynchronousFetchRequest error:&asynchronousFetchRequestError];
if (asynchronousFetchRequestError) {
NSLog(@"Unable to execute asynchronous fetch result.");
NSLog(@"%@, %@", asynchronousFetchRequestError, asynchronousFetchRequestError.localizedDescription);
}
}];
}
這給了我一個Enqueued from com.apple.main-thread (Thread 1)
錯誤。 這是我感到困惑的地方,因為我在主線程上運行此命令,並且認為我不需要在這里使用我的私有上下文。
關於我為什么在這里遇到並發問題的任何想法?
編輯:似乎其他人有確切的問題,並認為這是一個Xcode錯誤: CoreData異步獲取導致並發調試器錯誤
每個managedObject都有一個上下文。 每個上下文只有一個可以在其上運行的線程。 ManagedObjects不是線程安全的-甚至不可讀。 隨同帶有完成塊的托管對象傳遞是一個不好的做法。 很難弄清楚哪個ManagedObjects應該在哪個線程上。 同樣,即使您在正確的線程上傳遞它,也是一種不好的做法。 當您執行dispatch_async
,實體可能會在此期間從數據庫中刪除,並且訪問managedObject將導致崩潰。 優良作法是,應明確告知任何執行訪存的方法,並使用該上下文並同步返回。 在您的代碼中,該方法使用的是self.managedObjectContext
,但是我沒有辦法知道您在看與什么線程相關的代碼。 此外,指向上下文的指針可能會更改,並且可能會導致難以跟蹤的錯誤。
NSAsynchronousFetchResult
包含managedObjects,因此不是線程安全的,只能在該完成塊(在該對象的正確線程上運行)中使用。 您不能將它們傳遞給另一個線程。 如果您在一個塊中返回它們,那么該代碼也一定不能將它們傳遞給另一個線程。 您只需要對塊內的它們進行任何處理,然后將其丟棄即可。
如果您需要向用戶顯示信息,那么通常最好同步在主線程上進行獲取並獲取與主線程上下文關聯的ManagedObjects。 如果抓取時間太長,則應該解決該問題-沒有理由要花費太長時間。 在您的情況下,您似乎正在獲取數據庫中的所有項目。 那是一個錯誤。 您應該使用謂詞僅獲得所需的謂詞。
另一種可能性是將managedObjects的值復制到線程安全對象(字典或NSObject子類)中。
TL; DR您可能不需要NSAsynchronousFetchRequest。 在主線程上使用常規的提取請求,然后同步返回。 使用謂詞將結果限制為僅實際顯示的對象。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.