上下文模式?为啥 Core Data 需要它?

Posted

技术标签:

【中文标题】上下文模式?为啥 Core Data 需要它?【英文标题】:Context pattern? Why does Core Data need it?上下文模式?为什么 Core Data 需要它? 【发布时间】:2011-06-24 15:17:53 【问题描述】:

我对 Core Data 还是很陌生,我试图理解为什么它需要传递 NSManagedObjectContext。据我了解,需要传递上下文,以便多个线程不会影响同一个上下文,但我也觉得这种模式有时被认为是一种反模式,如 here 所述。

Core Data 理论上能否以线程安全的方式实现,从而避免使用这种模式?其他 ORM(例如 Ruby 的 ActiveRecord)如何避免这种模式?例如,CoreData 不能实现每个 NSManagedObject 的保存方法,例如在这个extension 中。这个轻量级框架不处理多线程,但是 NSManagedObjects 不能使用某种内部 GCD 队列来支持它,并且它们不会公开内部上下文吗?

抱歉,如果我遗漏了什么重要的东西。

【问题讨论】:

+1 好问题。我知道大上下文通常被视为一种反模式,但在我看来,Apple 并没有像一个初级程序员通过屋顶瓦片只是为了冲进浴室厕所那样滥用它。 NSManagedObjectContext 确实管理了很多事情,但通过方法而不要求您的所有实体一次可用或共享同一模型的 2 个实体相互了解。 【参考方案1】:

NSManagedObjectContext 是应用程序对象图的内存容器,就像持久存储(XML、SQLite 等)通常表示对象图的磁盘容器一样。

这种方法有一些优点:

    可以将故障应用于一组对象,或者在 CoreData 的情况下应用于整个对象图 这是一种方便的抽象,用于强制应用程序对其 I/O 进行批处理。 它提供了一个单一的联系点,可以有效地对整个对象图(NSFetchRequests 等)执行操作 撤消可以应用于对象图,而不仅仅是单个对象。

记住CoreData 不是一个ORM 框架也很重要,它是一个对象持久化框架。 CoreData 的主要职责是更高效地访问以持久格式存储在磁盘上的数据。但是,它不会尝试模拟关系数据库的功能。

关于并发性,即将发布的 Mac OSX 版本中引入了新的并发模型。您可以在 developer.apple.com 上阅读更多相关信息。

不过,抽象地说,为托管对象上下文选择的并发模型更多地与单个应用程序的细节有关,而不是上下文模式本身。 NSManagedObjectContext 的实例通常不应该在线程之间共享。

就像每个线程都需要它自己的 NSAutoReleasePool 实例一样,每个线程也应该有它自己的 MOC。这样,当线程完成执行时,它可以将其更改提交到磁盘上的存储区,然后释放上下文,释放线程上处理的对象消耗的所有内存。

与允许单个上下文在给定应用程序的生命周期内持续消耗系统资源相比,这是一种更有效的范例。当然,这也可以通过在 context 上调用 -reset 来完成,这将导致 context 使用的所有 NSManagedObject 都返回故障。

【讨论】:

【参考方案2】:

每个线程需要一个 NSManagedObjectContext。因此,您将有一个在主线程上填充您的 UI,而对于更长的操作,您将有一个用于每个后台线程。如果您希望从这些其他线程中合并结果,那么您可以订阅一个通知,该通知可以快速将更改的内容合并到您的主 MOC 中。

【讨论】:

与(如果 CoreData 提供)设置一种合并策略并让它自己合并内部创建的对象相比,自己进行此合并是否有优势?似乎如果它能够做到这一点,它将使使用它的 API 变得更加简单。

以上是关于上下文模式?为啥 Core Data 需要它?的主要内容,如果未能解决你的问题,请参考以下文章

iOS Core Data - 将上下文传递给详细视图的设计模式

Core Data 抛出 NSInternalInconsistencyException “100 次尝试后上下文仍然很脏。”

Core Data 3 托管对象上下文

使用Core Data将文本从文本字段分配到托管对象上下文

iOS Core Data - 如何避免同时保存多个上下文时崩溃?

Swift 3 Core Data - 如何同步保存上下文?