我有这个虚拟设置(用于测试可行性)。想法是: 当游戏首次启动时,我需要使用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的理解),如果你访问一个faulted
NSManagedObject
它激发并加载数据。但在这里,这不会发生。
不过,如果我(使用声明为那里的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时如何获得此结果?它甚至有可能吗?
让我知道你是否需要更多的代码或信息。谢谢!
噢好吧。虽然我知道它会创建一个新的'NSManagedObjectContext',我认为它将被创建为主队列中主要'managedObject'的子元素。这就是为什么我认为它可以工作。很高兴知道它不:D。然后,我必须找到一种方法来告诉“游戏单件”,它必须提取哪个“Site”。也许通过使用'startBase'的'ObjectID'? – Quantm
实际上,这个新的背景上下文是来自AppDelegate的'persistentContainer'的'viewContext'的子元素。然而,这并没有改变这个事实,即它是一个不同的上下文被取消分配的事实。至于为'Game'单例获取'Site'的想法,我认为使用'objectID'属性将是最简单和最安全的方法。 – user3581248
好的,谢谢。我尝试将'objectID'存储到'Game'单例中(在我保存了上下文之后),然后使用'managedObjectContext.object(with:)'来检索主队列中的'currentSite'。但它返回的对象仍然是一个错误。我不知道为什么。 – Quantm