簡書上的文章已經不再維護,有興趣閱讀其他文章,或一起交流的朋友,請移步 我的博客:punmy.cn
原文
這兩天在使用Core Data的過程中遇到了一個問題,在執行到managedObjectContext 的 -performBlock: 方法的時候,應用崩潰并提示:
- Can only use -performBlock: on an NSManagedObjectContext that was created with a queue
為何用 -performBlock:
我們之所以使用 performBlock: 方法,而不是直接進行 Core Data 的相關操作,是因為 Core Data 的操作不是線程安全的。
使用 -performBlock: 方法可以確保 Core Data 的相關操作都在 managedObjectContext 所在的線程上完成。
崩潰原因
崩潰的錯誤信息比較清楚的表明:“只能有和 queue 一起創建的NSManagedObjectContext 實例才能使用 -performBlock: 方法”。
這說明我們在創建 NSManagedObjectContext 實例的時候,沒有為它“分配”一個 queue。
下面我就為大家介紹一下實例化 NSManagedObjectContext 的正確姿勢。
正確姿勢
我們知道, iOS 9 開始,蘋果就在使用 Core Data 的項目中的 APPDelegate.m 中預先為我們提供了一份配置 Core Data Stack 的模板代碼。
這份代碼中就有默認的實例化 NSManagedObjectContext 的代碼。
- (NSManagedObjectContext *)managedObjectContext {
// Returns the managed object context for the application (which is already bound to the persistent store coordinator for the application.)
if (_managedObjectContext != nil) {
return _managedObjectContext;
}
NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
if (!coordinator) {
return nil;
}
_managedObjectContext = [[NSManagedObjectContext alloc] init]; //默認的實例化
[_managedObjectContext setPersistentStoreCoordinator:coordinator];
return _managedObjectContext;
}
這個默認的實例化代碼使用了 init 方法,這并不合適,因為這樣就不能為 NSManagedObjectContext 實例提供一個線程。我們需要將這個 init 方法替換成 -initWithConcurrency: 方法。這個方法配置了 NSManagedObjectContext 實例化所在的線程。
這就意味著我們要確定在哪個線程上實例化我們的 NSManagedObjectContext ,主線程,還是另外創建一個后臺線程。我們可以選擇的參數有:
- NSPrivateQueueConcurrencyType
- NSMainQueueConcurrencyType
在這里,我把它配置成在主線程上進行實例化(一般選擇主線程就可以)。代碼如下:
- (NSManagedObjectContext *)managedObjectContext {
// Returns the managed object context for the application (which is already bound to the persistent store coordinator for the application.)
if (_managedObjectContext != nil) {
return _managedObjectContext;
}
NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
if (!coordinator) {
return nil;
}
// since iOS 9
_managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
[_managedObjectContext setPersistentStoreCoordinator:coordinator];
return _managedObjectContext;
}
這樣問題就解決啦。
更詳細的內容可以參考Apple 官方文檔:
https://developer.apple.com/library/prerelease/ios/documentation/Cocoa/Reference/CoreDataFramework/Classes/NSManagedObjectContext_Class/#//apple_ref/c/tdef/NSManagedObjectContextConcurrencyType