iOS 9中實例化NSManagedObjectContext的正確姿勢 - Core Data

簡書上的文章已經不再維護,有興趣閱讀其他文章,或一起交流的朋友,請移步 我的博客: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

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 本文是對 MagicalRecord github上的翻譯 正文:注意: MagicalRecord 在 ARC...
    騂躍神話閱讀 2,039評論 1 5
  • 1.Difference between shallow copy and deep copy? 淺復制和深復制的...
    用心在飛閱讀 1,019評論 0 9
  • 之前看了很多面試題,感覺要不是不夠就是過于冗余,于是我將網上的一些面試題進行了刪減和重排,現在分享給大家。(題...
    Job_Yang閱讀 12,109評論 12 143
  • __block和__weak修飾符的區別其實是挺明顯的:1.__block不管是ARC還是MRC模式下都可以使用,...
    LZM輪回閱讀 3,358評論 0 6
  • Object-c的類可以多重繼承么?可以實現多個接口么?Category是什么?重寫一個類的方式用繼承好還是分類好...
    small_Sun閱讀 748評論 0 0