我们正在开发一个企业级应用程序,它将使用 Core Data 存储数以万计的对象,我们在几个方面遇到了问题。
我们的应用程序有几个独立的系统,它们在需要时对数据进行操作。这些系统包括项目的发现、项目的加载、同步和 UI 显示。如果我们正确地设计我们的软件,由于不同的系统修改相同的对象,应该几乎没有合并冲突。每个系统都有自己的操作队列,全部在后台执行。我们希望将所有对象的创建和修改都保留在后台,以最大限度地减少 UI 性能问题,尤其是在初始加速期间,可能会从服务器上的数据创建数千个对象。在这里,我们在各种设计尝试中遇到了几个问题。在这些加速过程中会消耗大量内存,并且所有上下文和子上下文的编排不正确,从而导致死锁和崩溃。我们尝试了以下设计:
NSPrivateQueueConcurrencyType
一个具有一个子上下文的根托管对象NSMainQueueConcurrencyType
上下文。UI 获取结果控制器使用此子上下文从中获取结果。从NSMainQueueConcurrencyType
子上下文中,我们创建了一个NSPrivateQueueConcurrencyType
名为“savingContext”的子上下文,每个后台操作都创建了该“savingContext”的一个子上下文,对其进行了更改,最后进行了我们所谓的“深度保存”,递归地保存到顶端。我们最初选择这种设计是为了不必处理NSManagedObjectContextDidSaveNotification
来自许多不同子上下文的通知。NSPrivateQueueConcurrencyType
我们包装了对上下文的每次调用和对对象的访问performBlockAndWait:
. 在功能上,这个设计执行了。所有更改和插入都保存到持久存储中,并且 UI 随更改而更新。至此,引入了两个问题。一个是在加速期间 UI 滞后,因为合并更改通过NSMainQueueConcurrencyType
子上下文,更重要的是,在加速期间内存使用率非常高。由于无法reset
递归调用上下文(因为主 UI 子上下文也在那里)和/或缺乏何时调用refreshObject:mergeChanges:
. 于是我们走了一条不同的路。- 有两个与持久存储协调器链接的顶级上下文,一个
NSPrivateQueueConcurrencyType
用于保存子上下文,一个NSMainQueueConcurrencyType
用于 UI 显示。NSMainQueueConcurrencyType
监听NSManagedObjectContextDidSaveNotification
来自主上下文的通知并将NSPrivateQueueConcurrencyType
它们合并到主线程中。每个后台操作创建一个主NSPrivateQueueConcurrencyType
上下文的子上下文,也具有私有队列并发类型,执行它的工作,递归执行“深度保存”,在当前上下文上执行保存,递归调用深度保存到其父, 在当前上下文中调用 reset 并再次保存。这样我们就避免了内存问题,因为创建的对象在保存后会很快释放。但是,通过这种设计,我们遇到了很多问题,例如死锁,NSInternalInconsistencyException
尽管有NSMainQueueConcurrencyType
上下文的保存通知,但异常和获取的结果控制器不会更新 UI。这也会导致 UI 中的初始加载时间变慢很多。在之前的设计中,获取结果控制器返回结果的速度非常快,而这会使 UI 阻塞几秒钟,直到视图加载(我们在 中初始化获取结果控制器viewDidLoad
)。
我们尝试了许多中间设计,但它们都围绕着相同的问题,要么是非常高的内存使用,要么是获取结果控制器不更新 UI,要么是死锁和NSInternalInconsistencyException
异常。
我真的越来越沮丧。我不能不觉得我们的设计对于一些应该相当简单的东西来说过于复杂了,只是我们缺乏对某些基本原理的理解正在扼杀我们。
那么大家有什么建议呢?对于我们的情况,您会推荐什么安排?我们应该如何管理不同线程中的不同上下文?释放插入对象和重置上下文的最佳实践?避免死锁?在这一点上,所有帮助将不胜感激。
我还看到了有关 MagicalRecords 类别的建议。推荐吗?我们已经投入使用 Core Data 类型,使用 MR 迁移会有多困难?