Ios Coredata非常慢;敏捷的
我制作了一个iOS应用程序来跟踪设备的gps路径。 问题是,当我跟踪超过5分钟时,coredata需要很长时间才能保存。 我保存了一个名为session的对象,session有很多位置对象。 位置对象为[[纬度,经度]] 会话对象看起来像[name:string,date:nsdate,平均速度:double,高速:double,行驶里程:double,位置:[[double,double]]Ios Coredata非常慢;敏捷的,ios,swift,core-data,Ios,Swift,Core Data,我制作了一个iOS应用程序来跟踪设备的gps路径。 问题是,当我跟踪超过5分钟时,coredata需要很长时间才能保存。 我保存了一个名为session的对象,session有很多位置对象。 位置对象为[[纬度,经度]] 会话对象看起来像[name:string,date:nsdate,平均速度:double,高速:double,行驶里程:double,位置:[[double,double]] 所以。。。它可以工作,但5分钟后就可以了。我认为保存需要2到3分钟如果有许多相同类型的对象,那么保存核
所以。。。它可以工作,但5分钟后就可以了。我认为保存需要2到3分钟如果有许多相同类型的对象,那么保存核心数据自然需要很长时间。不管你做什么,都需要一段时间。您可以做的是将保存配置为在后台线程中进行,以避免冻结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
}()
因为主上下文和父上下文都在内存中运行,所以从子上下文到父上下文的保存操作很快。一旦父对象拥有您的位置对象,它将保存在后台线程中。它可能仍然需要很长时间,但至少不应该冻结您的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)
}
}
}
(代码摘自Tim Roadley的《使用Swift学习iOS核心数据:实践指南》。为2020年更新
基本上,你必须使用核心数据提供的“替代上下文”
所以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 ...
}
}
在循环过程中
... 请特别注意不要在该循环中使用.viewContext。仅在循环内使用“pm”。如果调用其他代码,请特别小心。
例如,假设您有一个实用程序例程“查找某个项目”
或者可能是一个简单地抓住主要用户的实用程序例程
这些实用程序例程可能只是使用您常用的主上下文,core.container.viewContext
当您编写这样的实用程序例程时,很自然地只使用主上下文,而不考虑它
但是。在编写代码期间,在循环内部,很容易意外地使用这样一个实用程序例程
如果您这样做,应用程序将立即崩溃
在循环中的代码执行过程中,您不得在深层使用core.container.viewContext
您只能对任何核心数据使用“pm”,无论是在循环中还是从最终被调用的任何代码中,无论嵌套有多深,都可以使用“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
,它现在可以完美、顺利地工作。(关于如何做到这一点。)
在上面的bake()示例中,如果您确实添加了几行打印行来检查第二次保存中发生的情况,您将看到
…在主上下文中永远不会保存任何内容!
因此,在实践中,你的烘焙程序很简单
func bake() {
self.performAndWait {
if self.hasChanges {
do {
try self.save()
}
catch { print("bake disaster type 1 \(error)") }
}
}
最后一点。。。
请注意,整个烘焙实际上是在performAndWait
中调用的。但是,烘焙本身在performAndWait
中进行了重要的保存
我知道它的工作方式非常可靠
(很少有人讨论这个问题)建议需要一个内在的
但是:在我看来,您似乎不需要内部性能等待
所以可以想象烘焙更简单-
func bake() {
if self.hasChanges {
do {
try self.save()
}
catch {
print("woe \(error)")
}
}
}
当我尝试那种烘焙方式时,它似乎确实能很好地工作,没有任何问题。但是,对于核心数据,你必须测试几年才能发现问题
正如我在评论中提到的,我认为互联网上大约有两个地方解释了这一点,@AndyIbanez上面的原始答案,以及这个更新版本 在iOS模拟器或iPhone上工作?尝试退出一些应用程序以清理内存使用父上下文进行后台保存。此外,退出应用程序对加快速度几乎没有任何作用。您的UI是否冻结?如果要保存的对象很多,不管怎样都可能需要很长时间才能保存,但是使用父上下文进行保存可以避免UI冻结。是否混淆了变量名称?我不这么认为,但这个答案已经有两年多的历史了。它也是用Swift 2写的。我建议你检查一下我现在从哪里得到代码的那本书。这是整个网站上最重要的答案之一!正如@AndyIbanez提到的,这是几年前的事了,正如Ahmed提到的,我认为其中一个变量名被交换了。我已经为这个关键答案输入了当前的“公式”,这是宇宙中唯一一个解释核心数据的地方:/