我制作了一个iOS应用程序来跟踪该设备的全球定位系统路径。问题是,当我跟踪超过5分钟时,coredata需要很长时间来保存。我保存了一个名为session的对象,session有很多位置对象。位置对象是[纬度、经度]。
会话对象看起来像[名称:字符串,日期: nsdate,平均速度:双,高速:双,驱动公里:双,位置:[双,双]]
所以..。它能工作,但5分钟后。我想节省2到3分钟
发布于 2016-03-26 22:23:30
如果您有许多相同类型的对象,那么Core数据自然需要很长时间才能保存。不管你做什么,都需要一段时间。您可以做的是将保存配置为在后台线程中放置位置,以避免冻结您的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)
}
}
}(代码取自Tim的“使用Swift学习iOS核心数据:动手指南”一书)。
发布于 2020-02-16 14:07:36
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。
您只能在循环中或任何最终被调用的代码中对任何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()
}然而,在今天的实践中,您不需要对主要的上下文做任何事情:
"...and然后保存主上下文“的所有例子今天基本上都是错误的。
在今天的现实中,在99.9999%的情况下,您将使用.automaticallyMergesChangesFromParent = true,它现在工作得非常完美和顺利。(Example介绍了如何做到这一点。)
在上面的bake()示例中,如果您确实添加了几行打印行来检查第二次保存中发生了什么,您将看到.
...there绝不是要保存在主上下文中的任何东西!
因此,在实践中,你的烘焙程序很简单,
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)")
}
}
}当我尝试这种形式的烘焙,它似乎工作得很好,没有问题。但是,对于核心数据,你必须经过多年的测试才能发现问题。
正如我在评论中提到的,我认为在互联网上大约有两个地方解释了这一点,@AndyIbanez原来的答案,以及这个更新的版本!
https://stackoverflow.com/questions/36241172
复制相似问题