核心数据管理对象上下文设计建议

Leo*_*ica 9 multithreading core-data nsmanagedobjectcontext ios

我们正在开发一个企业级应用程序,它将使用Core Data存储数万个对象,并且我们在几个方面遇到了问题.


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

  • 一个根NSPrivateQueueConcurrencyType管理对象上下文,它有一个子NSMainQueueConcurrencyType上下文.UI获取的结果控制器使用此子上下文从中获取结果.从NSMainQueueConcurrencyType子上下文中,我们创建了一个NSPrivateQueueConcurrencyType子上下文,我们将其称为"savingContext",每个后台操作创建了一个"savingContext"的子上下文,进行了更改,最后执行了我们所谓的"深度保存",递归保存到顶端.我们最初选择此设计时不必处理NSManagedObjectContextDidSaveNotification来自许多不同子环境的通知.我们将对NSPrivateQueueConcurrencyType上下文的每次调用都包装起来并访问对象performBlockAndWait:.功能上,这个设计执行.所有更改和插入都保存到持久性存储中,并且UI已根据更改进行更新.这,介绍了两个问题.其中一个是在加速期间由于合并的更改而在延迟期间出现滞后的UI NSMainQueueConcurrencyType,更重要的是,在加速期间非常高的内存使用量.由于无法reset在上下文中递归调用(因为主UI子上下文也在那里)和/或缺乏知识何时调用,我们会遇到禁止的RAM使用refreshObject:mergeChanges:.所以我们走了一条不同的道路.
  • 有两个与持久性存储协调器链接的顶级上下文,一个NSPrivateQueueConcurrencyType用于保存子上下文,另一个NSMainQueueConcurrencyType用于UI显示.在NSMainQueueConcurrencyType以监听NSManagedObjectContextDidSaveNotification来自主通知NSPrivateQueueConcurrencyType上下文和合并它们在主线程.每个后台操作都创建主NSPrivateQueueConcurrencyType上下文的子上下文,也有私有队列并发类型,做它做什么,递归执行"深度保存",对当前上下文执行保存,深度保存到其父进程的递归调用,调用当前上下文重置并再次保存.这样我们就可以避免内存问题,因为创建的对象在保存后会很快释放.但是,通过这种设计,我们遇到了很多问题,例如死锁,NSInternalInconsistencyException异常和获取结果控制器尽管存在NSMainQueueConcurrencyType上下文的保存通知,但未更新UI .这也会导致UI中的初始加载时间减慢很多.在之前的设计中,获取的结果控制器非常快地返回结果,而这会阻止UI几秒钟直到视图加载(我们初始化获取的结果控制器viewDidLoad).

我们已经尝试了很多中间设计,但它们都围绕着相同的问题,即内存使用率非常高,获取的结果控制器没有更新UI或死锁和NSInternalInconsistencyException异常.


我真的很沮丧.我不禁觉得我们的设计对于一些应该相当简单的事情来说是过分复杂的,只是我们缺乏理解一些杀死我们的基本因素.


那么你们会建议什么?你会为我们的背景推荐什么安排?我们应该如何在不同的线程中管理不同的上下文?释放插入对象和重置上下文的最佳实践?避免死锁?在这一点上,所有的帮助将不胜感激.


我也看到了MagicalRecords类别的建议.推荐吗?我们已经投入使用核心数据类型,使用MR迁移有多难?

ado*_*oho 6

首先,为了管理您的内存,您的第二个架构为您提供了更大的灵活性.

其次,要管理的内存有两种:malloc-ed内存和驻留VM内存.您可以拥有较低的malloc内存占用空间,并且仍然具有较大的VM驻留区域.根据我的经验,这是因为Core Data积极地坚持新插入的项目.我通过保存后修剪通知解决了这个问题.

第三,MOC便宜.使用'和扔掉.换句话说,早期和经常释放内存.

第四,尝试在主要的MOC上几乎没有任何数据基础.是的,这听起来适得其反.我的意思是所有复杂的查询都应该在后台线程上完成,然后将结果传递给主线程,或者在利用现在填充的行缓存时从主线程重新执行查询.通过这样做,您可以保持UI的实时性.

第五,在我的多排队应用程序中,我尝试将所有保存都发生在后台.这使我的主要MOC保持快速且与来自网络的数据一致.

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