应该在哪里创建NSManagedObjectContext?

苏拉奇

我最近一直在学习有关核心数据的知识,尤其是关于如何对大量对象进行插入的知识。在学习了如何做到这一点并解决了我遇到的内存泄漏问题之后,我在Swift中编写了带有大型Core Data批处理插入的Q&A内存泄漏

改变之后NSManagedObjectContext从类属性的局部变量,并在一个节省时间分批,而不是一个刀片,它的工作好了很多。内存问题得以解决,速度得以提高。

我在答案中发布的代码是

let batchSize = 1000

// do some sort of loop for each batch of data to insert
while (thereAreStillMoreObjectsToAdd) {

    // get the Managed Object Context
    let managedObjectContext = (UIApplication.sharedApplication().delegate as! AppDelegate).managedObjectContext
    managedObjectContext.undoManager = nil // if you don't need to undo anything

    // get the next 1000 or so data items that you want to insert
    let array = nextBatch(batchSize) // your own implementation

    // insert everything in this batch
    for item in array {

        // parse the array item or do whatever you need to get the entity attributes for the new object you are going to insert
        // ...

        // insert the new object
        let newObject = NSEntityDescription.insertNewObjectForEntityForName("MyEntity", inManagedObjectContext: managedObjectContext) as! MyManagedObject
        newObject.attribute1 = item.whatever
        newObject.attribute2 = item.whoever
        newObject.attribute3 = item.whenever
    }

    // save the context
    do {
        try managedObjectContext.save()
    } catch {
        print(error)
    }
}

这种方法对我来说似乎很好。我在这里问一个问题的原因是,有两个人(他们对iOS的了解比我多得多)发表了我不理解的评论。

@Mundi说

在您的代码中似乎您使用的是相同的托管对象上下文,而不是新的上下文。

@MartinR还说

...“常规”实现是一个惰性属性,可在应用程序的整个生命周期内创建一次上下文。在这种情况下,您将重用Mundi所说的相同上下文。

现在我不明白。他们是说我正在使用相同的托管对象上下文还是应该使用相同的托管对象上下文?如果我正在使用相同的一个,它是如何创建的每个新的while循环?或者,如果我应该仅使用一个全局上下文,那么如何做到这一点而又不会导致内存泄漏?

以前,我在View Controller中声明了上下文,在中对其进行了初始化viewDidLoad,将其作为参数传递给执行插入操作的实用程序类,然后将其用于所有操作。发现大内存泄漏后,我才开始在本地创建上下文。

我开始在本地创建上下文的另一个原因之一是因为文档说:

首先,通常应该为导入创建一个单独的托管对象上下文,并将其撤消管理器设置为nil。(创建上下文并不是特别昂贵,因此,如果缓存持久性存储协调器,则可以对不同的工作集或不同的操作使用不同的上下文。)

标准的使用方式是NSManagedObjectContext什么?

乔迪·哈金斯(Jody Hagins)

现在我不明白。他们是说我正在使用相同的托管对象上下文还是应该使用相同的托管对象上下文?如果我使用相同的循环,那么如何在每个while循环上创建一个新循环?或者,如果我应该仅使用一个全局上下文,那么如何做到这一点而又不会导致内存泄漏?

让我们看一下代码的第一部分...

while (thereAreStillMoreObjectsToAdd) {
    let managedObjectContext = (UIApplication.sharedApplication().delegate as! AppDelegate).managedObjectContext
    managedObjectContext.undoManager = nil

现在,由于您似乎将MOC保留在App Delegate中,因此很可能正在使用模板生成的Core Data访问代码。即使您不是,managedObjectContext访问方法也极不可能在每次调用时都返回一个新的MOC。

您的managedObjectContext变量仅是对驻留在应用程序委托中的MOC的引用。因此,每次循环时,您只是在复制参考。每次循环,被引用的对象都是完全相同的对象。

因此,我认为他们说的是您没有使用单独的上下文,并且我认为他们是正确的。而是每次循环时都使用对相同上下文的新引用。


现在,您的下一组问题与性能有关。您的其他帖子引用了一些很好的内容。回去再看一遍。

他们的意思是,如果您想进行大量导入,则应创建一个单独的上下文,专门用于导入(由于我还没有时间去学习Swift,所以使用目标C)。

NSManagedObjectContext moc = [[NSManagedObjectContext alloc]
    initWithConcurrencyType:NSPrivateQueueConcurrencyType];

然后,您可以将该MOC附加到持久性存储协调器。performBlock然后,使用您将在单独的线程中导入对象。

批处理概念是正确的。你应该保持那个。但是,您应将每个批次包装在自动释放池中。我知道您可以迅速做到这一点...我只是不确定这是否是确切的语法,但我认为它已经接近了...

autoreleasepool {
    for item in array {
        let newObject = NSEntityDescription.insertNewObjectForEntityForName ...
        newObject.attribute1 = item.whatever
        newObject.attribute2 = item.whoever
        newObject.attribute3 = item.whenever
    }
}

用伪代码,看起来都像这样……

moc = createNewMOCWithPrivateQueueConcurrencyAndAttachDirectlyToPSC()
moc.performBlock {
    while(true) {
        autoreleasepool {
            objects = getNextBatchOfObjects()
            if (!objects) { break }
            foreach (obj : objects) {
                insertObjectIntoMoc(obj, moc)
            }
        }
        moc.save()
        moc.reset()
    }
}

如果有人想将伪代码转换为快速代码,我觉得很好。

自动释放池可确保在创建新对象后自动释放所有对象,这些对象将在每个批次的末尾释放。一旦释放了对象,MOC将在MOC中具有对对象的唯一引用,并且一旦发生保存,MOC应该为空。

诀窍是确保在批处理中创建的所有对象(包括代表导入数据的对象和托管对象本身)都在自动释放池中创建。

如果您执行其他操作(例如,提取以检查重复项)或具有复杂的关系,则MOC可能不会完全为空。

因此,您可能要[moc reset]在保存之后添加快速等效项,以确保MOC确实为空。

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Python

应该在哪里创建virtualenvs?

来自分类Dev

如何创建枚举或应该在哪里存储?

来自分类Python

应该在哪里创建虚拟环境?

来自分类Dev

应该在哪里创建片段?在viewModel或Activity中?

来自分类Java

我应该在哪里保存创建的文件?

来自分类Dev

我应该在哪里创建异常对象?

来自分类Dev

应该在哪里调用 setState ?

来自分类Dev

我应该在哪里修改?

来自分类Dev

应该在哪里应用AsNoTracking?

来自分类Dev

应该在哪里定义状态?

来自分类Dev

应该在哪里安装 SSL

来自分类Dev

应该在哪里抛出异常?

来自分类Dev

指针应该在哪里?

来自分类Dev

应该在哪里验证对象?

来自分类Dev

如何创建自定义别名以及我应该在哪里创建它?

来自分类Dev

我应该在哪里创建自定义文件夹?

来自分类Dev

首先应该在哪里创建Salesforce我的域?沙盒或生产

来自分类Dev

新数据对象的“ id”应该在哪里创建/分配?

来自分类Dev

通过工厂方法创建的对象应该在哪里删除?

来自分类Dev

React / Redux:我应该在哪里创建+放置“主”应用程序状态?

来自分类Dev

我应该在哪里在 Rails 中创建静态记录?

来自分类Dev

如果在 api 中创建失败,页面应该在哪里重定向

来自分类Dev

我应该在哪里在 Windows 服务中创建组合根?

来自分类Dev

我应该在哪里使用自己的DAG for Airflow创建文件夹?

来自分类Dev

我应该在哪里创建一个 after create 钩子

来自分类Dev

我应该在哪里为SwiftUI中的视图创建模型实例?

来自分类Dev

创建新库时,应该在哪里放置自定义错误类?

来自分类Dev

我应该在哪里声明静态实例?

来自分类Dev

我应该在哪里托管个人网站?

Related 相关文章

热门标签

归档