如何在除了从appDelegate获取之外的视图控制器中获取managedObjectContext?

8 浏览
0 Comments

如何在除了从appDelegate获取之外的视图控制器中获取managedObjectContext?

最近我了解到“你真的不应该调用AppDelegate来获取托管对象上下文”。苹果也在他们的文档中提到了这个建议。文档中写道:\n

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

\n此外,他们还提到了一些获取上下文的其他方法。到目前为止,我还无法理解他们在那里想表达什么。有人能否对此问题进行解释一下?任何支持陈述的代码片段都将非常受欢迎。\n编辑
\n

\n但有时,从应用程序、文档或视图控制器之外的其他地方检索上下文更容易或更适合。在基于Core Data的应用程序中,您可能会使用几个对象来保留对托管对象上下文的引用。托管对象本身有一个对自己上下文的引用,支持Core Data的各种控制器对象也是如此,例如数组和对象控制器(在OS X中是NSArrayController和NSObjectController,在iOS中是NSFetchedResultsController)。\n从这些对象中检索上下文的优点是,如果重新设计应用程序,例如使用多个上下文,您的代码可能仍然有效。例如,如果您有一个托管对象,并且想要创建一个与其相关的新托管对象,您可以询问原始对象的托管对象上下文,并使用该上下文创建新对象。这将确保您创建的新对象与原始对象位于同一个上下文中。\n

\n这到底是什么意思?我确定它与下面的最受欢迎答案不相似。有人能帮助我理解苹果文档中的这一部分吗?

0
0 Comments

问题的原因是作者想要在viewController中获取managedObjectContext,但不想通过appDelegate获取。为了解决这个问题,作者使用了单例模式来获取managedObjectContext。作者创建了一个名为"DataManager"的类,其中包含了所有的Core Data初始化方法,并且有对Managed Object Model和Context的公共引用。通过导入"DataManager.h"类并调用单例的方法,作者可以获取到数据。还有使用嵌套的Managed Object Contexts来处理复杂的情况,并将这个复杂性封装在"DataManager"类中。还有关于嵌套上下文的更多信息,提供了一个相关的文章链接。

文章中还提到了关于单例模式的讨论。有人认为单例模式会导致一些问题,比如无法进行单元测试,无法直接控制要推送到视图控制器的MOC等。但作者对此提出了自己的看法,认为使用单例模式可以方便地从任何视图控制器中调用同一个MOC,并且作者自己也从未遇到过问题。然而,对于测试来说,可以使用模拟MOC来测试VC和网络层的接口,并得到已知的答案。单例模式在避免依赖注入的同时,也会给自己带来一些不必要的困扰,因此应该尽量避免使用单例模式。

总结起来,作者通过使用单例模式来获取managedObjectContext,并在"DataManager"类中封装了所有与Core Data相关的初始化方法和公共引用。这种方法可以方便地从任何视图控制器中获取数据,并且可以处理复杂的情况。然而,单例模式也存在一些问题,比如无法进行单元测试和无法直接控制MOC的问题。因此,使用单例模式需要权衡利弊。

0
0 Comments

问题的原因是作者想要在视图控制器中获取managedObjectContext,但不想从appDelegate获取。解决方法是使用依赖注入的方式,即调用者/构造函数应该将NSManagedObjectContext设置到被调用/构造的对象中。

在AppDelegate中,应该将NSManagedObjectContext设置到与UIWindow相关联的rootViewController中。

rootViewController应该将NSManagedObjectContext设置到下一个视图控制器中,以此类推。

具体的方法是,视图控制器类中定义一个属性,并在调用时使用以下代码设置NSManagedObjectContext:

[nextViewController setManagedObjectContext:[self managedObjectContext]];

有些人可能会建议使用单例模式,但这是一个需要避免的陷阱。

更新:

依赖注入是最好的方法。

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

“将相同的上下文在控制器之间传递的缺点是,如果同一个实体在两个不同的位置进行修改,你必须处理合并冲突。”

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

在这种情况下,您的视图控制器应该监听托管对象的更改并对其做出反应。这样可以防止在UI中同时更新两个位置。用户无法同时关注两个位置,因此第二个位置将实时更新。

这是该问题的正确答案。

将两个实体放在同一个上下文中将确保其正常工作。多个上下文会导致内存中有两个具有相同数据的对象,但没有办法在不保存上下文的情况下注意到更改。

然而,如果您的视图控制器是在用户不干预的情况下修改数据,那么就有了一个单独的问题。视图控制器用于用户修改或查看数据,不是用于任何数据后台处理的地方。

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

在这种情况下,您确实有可能发生合并冲突,并且需要为发生的情况编写代码。第一步是更改NSManagedObjectContext实例上的合并策略。

更新:

我怀疑您误读了该文档。

该文档描述的是从NSManagedObject实例中获取NSManagedObjectContext的能力。这是非常有用的。例如,一个视图控制器具有添加或编辑对象的功能。通过仅将NSManagedObject推送到视图控制器,您可以控制和决定该视图控制器将要处理的内容。接收视图控制器知道它需要允许对接收到的NSManagedObject进行编辑。它不关心它正在使用哪个NSManagedObjectContext。它可以使用主上下文,可以使用子上下文,可以在单元测试中隔离使用,它无需知道或关心。它只是显示从它手中接收到的NSManagedObject的数据,并在用户选择保存编辑时保存相关的NSManagedObjectContext。

该文档并不建议将NSManagedObjectContext存在某个通用位置(即单例)。它建议如果有另一种访问与NSManagedObject相关联的NSManagedObjectContext的方式,那么使用它是可以的,而且是很有意义的。

我知道这种方法,但是对于这个方法得到了不同的反应。有一个说法是“将相同的上下文在控制器之间传递的缺点是,如果在两个不同的位置修改了同一个实体,你必须处理合并冲突。”我在某个地方读到过提到的方法更好。我试图回顾一下那篇文章。所以,不确定您的方法是否真的是一个好方法。希望能有更好的解释和替代方法。对于替代方法给一个赞,但并不确信。

请参阅我的问题的编辑部分。它是否提出了其他更好的方法?

太棒了...非常感谢。您给了我清晰的认识。接受了 🙂

我一直在为此苦苦挣扎,谢谢!

0