访问由私有managedObjectContext创建的CoreData对象(在后台线程中创建)

时间:2017-02-28 19:40:06

标签: ios swift core-data nsmanagedobjectcontext

我有这个虚拟设置(用于测试可行性)。想法是: 当游戏首次启动时,我需要使用CoreData将一大堆数据(存储在plists中)复制到数据库中。我想在全局后台队列中执行此操作(以便UI仍然响应)。

这就是我尝试做的事情:

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,它会触发并加载数据。但在这里,这不会发生。

但是,如果我在主队列中运行GameSetupController.setup(withManagedObjectContext: managedObjectContext)(使用在那里声明的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 =     (
    );
}))

这就是我想要的。在后台队列中使用私有managedObjectContext时,如何获得此结果?它甚至可能吗?

如果您需要更多代码或信息,请与我们联系。谢谢!

1 个答案:

答案 0 :(得分:1)

您正在使用的方法,performBackgroundTask实际上

  

创建一个新的NSManagedObjectContext,并将concurrencyType设置为NSPrivateQueueConcurrencyType。

Source

这意味着您打印Game.shared.currentSite对象时可能会释放此上下文。而且由于它是在不再存在的上下文中创建的,因此没有办法解决它。

基本上你在后台线程中填充数据库的想法是正确的,你只需要从主上下文中获取Game.shared.currentSite对象,这样它就可以在应用程序运行时继续运行。 / p>

更新:

此外,如果您使用print方法调试CoreData对象,请记住它不会导致它们出现故障。您可以尝试打印一些属性 - 这应该会显示非故障是否正常。