【问题标题】:How to get managedObjectContext for viewController other than getting it from appDelegate?除了从 appDelegate 获取之外,如何获取 viewController 的 managedObjectContext?
【发布时间】:2014-01-29 18:51:29
【问题描述】:

最近我开始知道“你真的不应该调用 AppDelegate 来获取托管对象上下文”。 Apple 还将此建议写入其文档here。 它是这样的:

视图控制器通常不应该从全局对象(例如应用程序委托)中检索上下文——这使得应用程序架构变得僵化。视图控制器也不应该为自己的使用创建上下文(除非它是嵌套上下文)。这可能意味着使用控制器的上下文执行的操作没有注册到其他上下文,因此不同的视图控制器对数据有不同的看法。

他们还提到了其他一些获取上下文的方法。到目前为止,我无法弄清楚他们想在那里说什么。任何人都可以对这个问题有所了解。任何代码 sn-p 支持语句都将受到欢迎。

编辑

不过,有时检索 来自应用程序或文档之外的某个地方的上下文,或者 视图控制器。您可能会在基于核心数据的项目中使用的几个对象 应用程序保留对托管对象上下文的引用。托管 对象本身具有对其自身上下文的引用,各种 支持 Core Data 的控制器对象,例如数组和对象 控制器(OS X 中的 NSArrayController 和 NSObjectController,以及 iOS 中的 NSFetchedResultsController)。

从这些对象之一中检索上下文具有优势 如果你重新设计你的应用程序,例如使用 多个上下文,您的代码可能仍然有效。例如, 如果您有一个托管对象,并且您想创建一个新的托管对象 与它相关的对象,您可以向原始对象询问其 托管对象上下文并使用它创建新对象。这会 确保您创建的新对象与 原创。

究竟是什么?确信它与下面高度投票的答案不相似。有人可以帮我理解这部分 Apple 文档吗?

【问题讨论】:

  • 绝对不要使用应用代理。如果您必须使用全局对象,请将其放在一个单例中,其名称反映了它包含该数据库。
  • @uliwitness 我很想知道,为什么不 appDelegate 以及为什么另一个单身人士可以?
  • 因为应用委托被命名为“应用委托”。它旨在执行与整个应用程序有关的事情以及如何从外部感知它(停靠菜单、打开文件等)。它是特定于这一应用程序的代码,并且设计上不可重用。其他单例独立于这个特定的应用程序。此外,您的单身人士有一个更精确的名称。如果你把这样的东西放在应用程序委托中,它会收集废话,因为单例的所有东西都是“用于整个应用程序”的。
  • 不建议使用应用代理可能是因为如果您需要引入新的 MOC,那么设置允许更多“模块化”代码。它更多地抱怨 OO 架构。
  • "在控制器之间传递相同上下文的缺点是,如果同一个实体在两个不同的地方被修改,您必须管理合并冲突。"在 iOS 中通常不是问题,因为您通常一次只能看到一个视图控制器

标签: ios objective-c core-data nsmanagedobjectcontext appdelegate


【解决方案1】:

称为依赖注入。基本上,调用者/构造函数应该将NSManagedObjectContext 设置为被调用/构造函数。

在您的AppDelegate 中,您应该将NSManagedObjectContext 设置为与UIWindow 关联的rootViewController

然后您的rootViewController 应将NSManagedObjectContext 设置为下一个视图控制器,依此类推。

怎么样?它只是视图控制器类的一个简单属性,调用者使用:

[nextViewController setManagedObjectContext:[self managedObjectContext]];

其他人可能会推荐单例,但这是另一个最好避免的深坑。

更新

依赖注入是最好的方法。

这是 Apple 设计的方法。另一种选择涉及某种形式的单例:AppDelegate 或另一种。

“在控制器之间传递相同上下文的缺点是,如果在两个不同的地方修改了相同的实体,则必须管理合并冲突。”

这是一个完全不同的问题,它不会通过多个 NSManagedObjectContext 实例来解决。事实上,多个实例会使情况变得更糟并保证合并冲突。

在这种情况下,您的视图控制器应该监听托管对象的变化并对它们做出反应。使其无法同时在 UI 中的两个位置进行更新。用户根本无法同时关注两个地方,因此第二个位置将实时更新。

这是该问题的正确答案。

将两个实体放在同一上下文中将确保其正常工作。多个上下文将导致它们成为内存中具有相同数据的两个对象,并且如果不保存到上下文,就无法注意到更改。

但是,如果您的视图控制器在没有用户干预的情况下修改数据,那么您将遇到一个单独的问题。视图控制器供用户修改或查看数据。它们不是对任何类型的数据进行后台处理的地方。

如果您处于进口情况,那么这与您提出的问题不同。在这种情况下,您(应该)使用多个线程(UI 线程、导入线程)并且您必须为每个线程至少拥有一个上下文。

在这种情况下,您确实面临合并冲突的风险,您需要针对发生的情况编写代码。第一步是更改 NSManagedObjectContext 实例的合并策略。

更新

我怀疑您误读了该文档。

描述的是从NSManagedObject 实例中获取NSManagedObjectContext 的能力。这绝对有用。以能够添加或编辑对象的视图控制器为例。通过justNSManagedObject 推送到视图控制器,您可以控制并决定视图控制器将要触摸的内容。接收视图控制器知道它需要允许编辑接收到的NSManagedObject。它不关心它正在使用什么NSManagedObjectContext。它可能与主一起工作,它可能与孩子一起工作,它可能在单元测试中被隔离,它不需要知道或关心。如果用户选择保存编辑,它只显示来自NSManagedObject 的数据并保存关联的NSManagedObjectContext

该文档并不建议为您的NSManagedObjectContext 提供一些通用位置(又名单身人士)。这表明如果您有其他方法可以访问与NSManagedObject 关联的NSManagedObjectContext,那么这样做是可以的,而且这样做绝对有意义。

【讨论】:

  • 我知道这种方法,但对此反应不一。有这样的说法“在控制器之间传递相同上下文的缺点是,如果在两个不同的地方修改了同一个实体,则必须管理合并冲突。”在某处我读到有问题的方法比你提到的方法好。我正试图回顾那篇文章。所以,不确定你的方法是否真的是一个好方法。希望有更好的解释和替代方案。 1 为替代方案,但不相信.. 抱歉
  • 请参阅我的问题的编辑部分。它是否暗示了其他更好的方法?
  • 太棒了……太感谢了。你在这里给了我清晰的图片..接受:)
  • 我一直在努力解决这个问题,谢谢!
【解决方案2】:

在获取托管对象上下文时,单例方法最适合我。这实际上取决于您的应用程序的复杂性,但在我的情况下,我通常会保留一个托管对象上下文,并在需要进行更改时使用临时嵌套上下文。

通过使用基于单例的“DataManager”类,该类包含所有核心数据初始化方法以及对托管对象模型和上下文的公共引用,我可以通过导入我的“DataManager.h”类和调用单例:

// I have a method to create an object that requires the Manage Object Context, so I call it from the DataManager singleton
SomeObject *newObject = [SomeObject createObjectInContext:[[DataManager sharedInstance] managedObjectContext]];

// I have a method in DataManager to save the context
[[DataManager sharedInstance] saveContext];

其实就是简化版。我通常使用嵌套的托管对象上下文,以便在用户确认添加或修改托管对象之前不会修改我的主要托管对象上下文。这种复杂性都可以包含在“DataManager”类中。

这有点离题,但如果您需要了解有关嵌套上下文的更多信息:我在不使用嵌套上下文来更改主托管对象上下文时遇到了严重问题。这篇文章虽然有些超出我的想象,但帮助我理解和实现了嵌套上下文:

http://www.cocoanetics.com/2012/07/multi-context-coredata/

【讨论】:

  • 将您的核心数据代码(堆栈、迁移等)放入单个处理程序是一个可靠的建议。使它成为一个单例不是。使用单例,您无法进行单元测试,无法直接控制将哪个 MOC 推送到视图控制器以及其他问题。
  • 我正在使用单元测试(它在学习列表中),但是关于单例方法,单例中不是只有一个 MOC 可以从任何调用给VC?我不想绕开这个问题的主题,但我想了解您关于“无法直接控制正在推送哪个 MOC”的说法。只有一个 MOC,如果需要更改,我会创建一个临时嵌套 MOC,然后将更改保存回主 MOC 或丢弃临时 MOC。这种方法我从来没有遇到过问题,但这并不意味着它们不存在......
  • 以插入/编辑视图为例。在编辑时,我可以从主 MOC 推送 MO。在插入时,我可以创建一个新的 MOC,创建一个与之关联的 MO,然后将该 MO 发送到 VC。 VC不需要关心。对于测试,我可以模拟 MOC 并测试到我的 VC/网络层等的接口,并获得已知的答案。为了避免依赖注入的单一目的,单例使所有这些变得更加困难。单身人士最终会将您描绘成不必要的角落,并且确实是应该避免的黑客行为。谷歌“单身是邪恶的”并阅读:)
猜你喜欢
  • 2013-08-26
  • 1970-01-01
  • 2010-12-26
  • 1970-01-01
  • 2014-08-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多