核心数据pipe理对象上下文devisebuild议

我们正在研究一个企业级的应用程序,它将存储数以万计的核心数据对象,我们在几个方面都有问题。


我们的应用程序有几个独立的系统,在需要时对数据进行操作。 这些系统包括项目的发现,项目的加载,同步和UI显示。 如果我们正确地devise我们的软件,由于不同的系统修改相同的对象,应该有很less的甚至没有合并冲突。 每个系统都有自己的操作队列,全部在后台执行。 我们希望在后台保留所有对象的创build和修改,以最大限度地减lessUI性能问题,特别是在初始阶段,可能会从服务器上的数据创build数千个对象。 在这里我们遇到了几个与我们的各种devise尝试的问题。 在这些上升过程中巨大的内存消耗,以及所有上下文和子上下文的错误编排,导致死锁和崩溃。 我们尝试了以下devise:

  • 一个拥有一个子NSMainQueueConcurrencyType上下文的根NSPrivateQueueConcurrencyType托pipe对象上下文。 UI获取的结果控制器使用此子上下文从中获取结果。 从NSMainQueueConcurrencyType子上下文中,我们创build了一个NSPrivateQueueConcurrencyType子上下文,我们称之为“savingContext”,每个后台操作创build了“savingContext”的子上下文,做了修改,最后做了我们所谓的“深度保存”保存到顶部。 我们最初select这种devise,不必处理来自许多不同的子上下文的NSManagedObjectContextDidSaveNotification通知。 我们将每个调用都包装到NSPrivateQueueConcurrencyType上下文中,并使用performBlockAndWait:来访问对象。 在function上,这个devise进行。 所有更改和插入已保存到持久性存储,并更新了UI的更改。 这个,介绍了两个问题。 其中一个是laggy UI,因为合并后的更改通过NSMainQueueConcurrencyType子上下文,更重要的是,在启动期间非常高的内存使用率。 由于无法在上下文上recursion调用reset (因为主UI子上下文也存在)和/或缺less何时调用refreshObject:mergeChanges: 所以我们走了一条不同的路
  • 有两个顶级上下文链接到持久性存储协调器,一个用于保存子上下文的NSMainQueueConcurrencyType和一个用于UI显示的NSMainQueueConcurrencyTypeNSMainQueueConcurrencyType侦听来自主NSPrivateQueueConcurrencyType上下文的NSManagedObjectContextDidSaveNotification通知,并将它们合并到主线程中。 每个后台操作都创build主NSPrivateQueueConcurrencyType上下文的子上下文,也使用私有队列并发types,做它所做的事情,recursion地执行“深度保存”,在当前上下文执行保存,深度保存到其上下文的recursion调用父母,调用当前上下文重置并再次保存。 这样我们可以避免内存问题,因为创build的对象在保存后快速释放。 但是,通过这种devise,我们遇到了很多问题,例如NSInternalInconsistencyExceptionNSInternalInconsistencyExceptionexception和获取的结果控制器不更新UI,尽pipe保存NSMainQueueConcurrencyType上下文的通知。 这也会导致UI中的初始加载时间减慢很多。 在之前的devise中,抓取的结果控制器返回结果的速度非常快,而这会阻塞UI几秒钟,直到视图加载(我们在viewDidLoad初始化抓取的结果控制器)。

我们已经尝试了许多中间devise,但都围绕相同的问题,无论是非常高的内存使用率,获取的结果控制器不更新UI或死锁和NSInternalInconsistencyExceptionexception。


我真的感到沮丧。 我不得不觉得,我们的devise显然是复杂的,应该是相当简单的事情,只是我们不了解一些基本的东西正在杀死我们。


那么你们会build议什么? 你会根据我们的情况推荐什么样的安排? 我们应该如何在不同的线程中pipe理不同的上下文? 释放插入的对象和重置上下文的最佳实践? 避免死锁? 所有的帮助,将在此时赞赏。


我也看到了MagicalRecords类别的build议。 是否推荐? 我们已经投入使用核心数据types,使用MR迁移有多困难?

首先,为了pipe理你的记忆,你的第二个架构给你更多的灵活性。

其次,要pipe理两种内存:malloc-ed内存和常驻虚拟机内存。 你可以有一个低malloc-ed的内存占用,并且仍然有一个大的VM驻留区域。 根据我的经验,这是因为Core Data积极地坚持新插入的项目。 我通过保存后修剪通知来解决这个问题。

第三,MOC便宜。 使用和扔掉他们。 换句话说,尽早释放内存。

第四,尝试在主要的商务部门上做几乎没有明智的数据库。 是的,这听起来适得其反。 我的意思是,所有复杂的查询都应该在后台线程上完成,然后将结果传递给主线程,或者在利用现在填充的行caching的同时从主线程中重新执行查询。 通过这样做,您可以保持UI的生动。

第五,在我的大量多人排队的应用程序中,我尝试着将所有的保存真的发生在后台。 这使我的主要MOC与从networking进入的数据保持一致。

第六,NSFetchedResultsController是一个非常有用但专业的控制器。 如果您的应用程序将其推到了其能力范围之外,它将开始locking您的界面。 当发生这种情况时,我通过自己监听-didSave通知来控制自己的控制器。