Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/ios/93.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ios Coredata非常慢;敏捷的_Ios_Swift_Core Data - Fatal编程技术网

Ios Coredata非常慢;敏捷的

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分钟如果有许多相同类型的对象,那么保存核

我制作了一个iOS应用程序来跟踪设备的gps路径。 问题是,当我跟踪超过5分钟时,coredata需要很长时间才能保存。 我保存了一个名为session的对象,session有很多位置对象。 位置对象为[[纬度,经度]]

会话对象看起来像[name:string,date:nsdate,平均速度:double,高速:double,行驶里程:double,位置:[[double,double]]


所以。。。它可以工作,但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提到的,我认为其中一个变量名被交换了。我已经为这个关键答案输入了当前的“公式”,这是宇宙中唯一一个解释核心数据的地方:/