我制作了一款iOS应用程序,用于跟踪设备的gps路径。 问题是,当我跟踪超过5分钟时,coredata需要很长时间才能保存。 我保存了一个名为session的对象,session有很多位置对象。 位置对象是[[纬度,经度]]
并且会话对象看起来像[name:string,date:nsdate,average speed:double,high speed:double,driven km:double,locations:[[double,double]]]
所以...它有效,但5分钟后。我认为需要2到3分钟才能保存
答案 0 :(得分:5)
基本上,您必须使用 当今由核心数据提供的“替代上下文”。
因此core.container
是“您的”容器……很可能来自您的核心数据堆栈单例。
因此,您的世界鸟类数据库有了新的数据……
let pm = core.container.newBackgroundContext()
pm.perform {
for oneBudgie in someNewData {
... create your new CDBudgie entity ...
... take EXTREME care to use "pm" throughout ...
... take EXTREME care to NEVER use .viewContext throughout ...
}
}
在循环中,
例如,您有一个“查找特定项目”的实用程序。
或者是可以简单地抓住主要用户的实用程序。
这些实用程序例程可能仅使用您通常的主上下文,core.container.viewContext
。
编写此类实用程序例程时,自然会使用主上下文,而不用考虑它。
但是。在代码中,在循环内意外使用这样的实用程序例程非常容易。
如果这样做,该应用将立即崩溃。
在循环内的代码中,切勿在深处意外地使用core.container.viewContext
。
对于循环内的任何CoreData或任何最终被调用的代码,无论嵌套在其中的深度如何,您都只能使用“ pm”。
在创建所有新项目之后,看来您正是在这样做:
func bake() {
self.performAndWait {
if self.hasChanges {
do {
try self.save()
}
catch { print("bake disaster type 1 \(error)") }
}
// BUT SEE NOTES BELOW
if core.container.viewContext.hasChanges {
do {
try core.container.viewContext.save()
}
catch { print("bake disaster type 2 \(error)") }
}
// BUT SEE NOTES BELOW
}
}
据我所知。没人真正知道,但是据我所知。
因此
let pm = core.container.newBackgroundContext()
pm.perform {
for oneBudgie in someNewData {
... create your new CDBudgie entity ...
... be absolutely certain to only use 'pm' ...
}
pm.bake()
}
今天“ ...然后保存主要上下文”的所有许多示例基本上都是错误的。
在现实中,在99.9999%的情况下,您将使用.automaticallyMergesChangesFromParent = true
,它现在可以完美流畅地运行。 (如何操作的Example。)
在上面的bake()示例中,如果从字面上添加几个打印行以检查第二次保存中发生了什么,您将看到...
因此,实际上,您的烘焙程序很简单,
func bake() {
self.performAndWait {
if self.hasChanges {
do {
try self.save()
}
catch { print("bake disaster type 1 \(error)") }
}
}
请注意,整个烘烤实际上是在performAndWait
内部进行的。但是,烘烤本身可以在performAndWait
内部进行重要的保存。
我确实知道它那样非常可靠。
(讨论此问题的人很少)建议需要内部的。
但是:在我看来,您 不需要 内部performAndWait
。
所以可以想象,烘烤甚至更简单-
func bake() {
if self.hasChanges {
do {
try self.save()
}
catch {
print("woe \(error)")
}
}
}
当我尝试这种形式的烘烤时,它似乎效果很好,没有任何问题。但是,然后,使用Core Data,您必须测试好几年才能发现问题。
正如我在评论中提到的那样,我认为互联网上大约有2个地方可以对此进行解释,上面的@AndyIbanez原始答案以及此更新的版本!
答案 1 :(得分:2)
如果您有许多相同类型的对象,Core Data自然会花费很长时间来保存。不管你做什么都不重要,需要一段时间。您可以做的是将保存配置为在后台线程中进行,以便不冻结您的UI。
最简单的方法是为主要上下文创建背景上下文。这个想法是您的主上下文将其数据保存到父上下文,父上下文负责将数据持久保存到磁盘。基本上是这样的:
因为主要上下文和父上下文都在内存中运行,所以从子节点到父节点的保存操作很快。一旦父项具有您的位置对象,它将保存在后台线程中。它可能仍需要很长时间,但至少它不应该冻结你的UI。
您可以在代码中对此进行配置:
lazy var parentContext: NSManagedObjectContext = {
let moc = NSManagedObjectContext(concurrencyType:.PrivateQueueConcurrencyType)
moc.persistentStoreCoordinator = self.coordinator
return moc
}()
lazy var context: NSManagedObjectContext = {
let moc = NSManagedObjectContext(concurrencyType:.MainQueueConcurrencyType)
// moc.persistentStoreCoordinator = self.coordinator
moc.parentContext = self.parentContext
return moc
}()
context
将是子上下文。你可以看到给它一个父上下文是多么容易。
然后,保存您的数据:
class func save(moc:NSManagedObjectContext) {
moc.performBlockAndWait {
if moc.hasChanges {
do {
try moc.save()
} catch {
print("ERROR saving context \(moc.description) - \(error)")
}
}
if let parentContext = moc.parentContext {
save(parentContext)
}
}
}
(代码采用并稍微编辑了" iOS的学习核心数据与Swift:动手指南" Tim Roadley的书)。