2017-02-28 75 views
0

我有這個虛擬設置(用於測試可行性)。想法是: 當遊戲首次啓動時,我需要使用CoreData將大量數據(存儲在plists中)複製到數據庫。我想在全局背景隊列中這樣做(這樣UI仍然可以響應)。訪問由私有managedObjectContext創建的CoreData對象(在後臺線程中創建)

這就是我嘗試做:

appDelegate.persistentContainer.performBackgroundTask { (managedObjectContext) in 
    GameSetupController.setup(withManagedObjectContext: managedObjectContext) 
} 

我開始backgroundTask和調用方法上我GameSetupController。它看起來像這樣:

static func setup(withManagedObjectContext managedObjectContext: NSManagedObjectContext) { 
    let startCoords = Coordinates(atQuadrant: 153, galaxy: 42, system: 3, using: managedObjectContext) 
    let startPlanet = Planet(atCoordinates: startCoords, withName: "Planet 1", using: managedObjectContext) 
    let startBase = Site(atPlanet: startPlanet, withName: "Name of base", belongingToPlayer: true, using: managedObjectContext) 

    // Game is a singleton 
    Game.shared.currentSite = startBase 

    do { 
     try managedObjectContext.save() 
    } catch let error as NSError { 
     fatalError("Couldn't save to database. Error: \(error.debugDescription)") 
    } 
} 

Game singleton用於存儲當前的遊戲特性,如Site用戶當前所在的位置。

後臺任務完成後,我想打印Game.shared.currentSite(來自主隊列)。這就是我得到:

Optional(<Site: 0x17008c080> (entity: Site; id: 0xd000000000100004 <x-coredata://5D8B1335-5F8F-4E66-BC3F-DA7C7AA2B54B/Site/p4> ; data: <fault>)) 

通常情況下(這是我的CoreData的理解),如果你訪問一個faultedNSManagedObject它激發並加載數據。但在這裏,這不會發生。

不過,如果我(使用聲明爲那裏的managedObjectContext)在主隊列中運行GameSetupController.setup(withManagedObjectContext: managedObjectContext)我得到這個:

Optional(<Site: 0x170092610> (entity: Site; id: 0xd000000000140004 <x-coredata://5D8B1335-5F8F-4E66-BC3F-DA7C7AA2B54B/Site/p5> ; data: { 
    belongsToPlayer = 1; 
    buildings =  (
    ); 
    coordinates = "0xd000000000140000 <x-coredata://5D8B1335-5F8F-4E66-BC3F-DA7C7AA2B54B/Coordinates/p5>"; 
    events =  (
    ); 
    name = "Main Base I"; 
    planet = "0xd000000000140002 <x-coredata://5D8B1335-5F8F-4E66-BC3F-DA7C7AA2B54B/Planet/p5>"; 
    resources = nil; 
    spaceships =  (
    ); 
})) 

這就是我想要的。在後臺隊列中使用private managedObjectContext時如何獲得此結果?它甚至有可能嗎?

讓我知道你是否需要更多的代碼或信息。謝謝!

回答

1

您所使用的方法,performBackgroundTask實際上

創建一個新的NSManagedObjectContext設置爲NSPrivateQueueConcurrencyType的concurrencyType。

Source

這意味着,這種情況下可能會得到你所打印Game.shared.currentSite對象的時間釋放。而且由於它是在這個不再存在的上下文中創建的,因此無法無故障地進行。

基本上你的想法是在後臺線程中填充數據庫是好的和正確的,你只需簡單地從主要上下文獲取Game.shared.currentSite對象,這樣它就可以在應用程序運行時繼續運行。

UPDATE:

另外,如果你使用print方法來調試CoreData對象,請記住,它不會引起他們對聯合國的錯。你可以嘗試打印他們的一些屬性 - 這應該會告訴你如果沒有錯誤的話很好。

+0

噢好吧。雖然我知道它會創建一個新的'NSManagedObjectContext',我認爲它將被創建爲主隊列中主要'managedObject'的子元素。這就是爲什麼我認爲它可以工作。很高興知道它不:D。然後,我必須找到一種方法來告訴「遊戲單件」,它必須提取哪個「Site」。也許通過使用'startBase'的'ObjectID'? – Quantm

+0

實際上,這個新的背景上下文是來自AppDelegate的'persistentContainer'的'viewContext'的子元素。然而,這並沒有改變這個事實,即它是一個不同的上下文被取消分配的事實。至於爲'Game'單例獲取​​'Site'的想法,我認爲使用'objectID'屬性將是最簡單和最安全的方法。 – user3581248

+0

好的,謝謝。我嘗試將'objectID'存儲到'Game'單例中(在我保存了上下文之後),然後使用'managedObjectContext.object(with:)'來檢索主隊列中的'currentSite'。但它返回的對象仍然是一個錯誤。我不知道爲什麼。 – Quantm

相關問題