访问由私有 managedObjectContext 创建的 CoreData 对象(在后台线程中创建)
Access CoreData objects created by a private managedObjectContext (created in a background thread)
我有这个虚拟设置(用于测试可行性)。想法是:
当游戏第一次开始时,我需要使用 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 时如何获得此结果?有可能吗?
如果您需要更多代码或信息,请告诉我。谢谢!
你使用的方法,performBackgroundTask
实际上
creates a new NSManagedObjectContext with the concurrencyType set to NSPrivateQueueConcurrencyType.
这意味着这个上下文可能会在您打印 Game.shared.currentSite
对象时被释放。由于它是在这个不再存在的上下文中创建的,因此无法消除它的错误。
基本上你在后台线程中填充数据库的想法是正确的,你只需要从主上下文中获取 Game.shared.currentSite
对象,这样它就会在应用程序运行时继续运行 运行.
更新:
此外,如果您使用 print
方法来调试 CoreData 对象,请记住它不会导致它们解除错误。您可以尝试打印它们的一些属性 - 这应该会告诉您是否正确无误。
我有这个虚拟设置(用于测试可行性)。想法是:
当游戏第一次开始时,我需要使用 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 时如何获得此结果?有可能吗?
如果您需要更多代码或信息,请告诉我。谢谢!
你使用的方法,performBackgroundTask
实际上
creates a new NSManagedObjectContext with the concurrencyType set to NSPrivateQueueConcurrencyType.
这意味着这个上下文可能会在您打印 Game.shared.currentSite
对象时被释放。由于它是在这个不再存在的上下文中创建的,因此无法消除它的错误。
基本上你在后台线程中填充数据库的想法是正确的,你只需要从主上下文中获取 Game.shared.currentSite
对象,这样它就会在应用程序运行时继续运行 运行.
更新:
此外,如果您使用 print
方法来调试 CoreData 对象,请记住它不会导致它们解除错误。您可以尝试打印它们的一些属性 - 这应该会告诉您是否正确无误。