我同意@Abizern:NSManagedObjectContext
在你的代码中传递一个实例,而不是依赖你的应用程序委托、全局变量或自定义助手单例。
依赖注入
如果您知道某些控制器需要访问,NSManagedObjectContext
请在其 init 方法中添加一个参数并保持对其的强引用:
@interface SomeController : NSObject
@property (nonatomic, strong, readwrite) NSManagedObjectContext *context;
- (instancetype)initWithContext:(NSManagedObjectContext *)context;
@end
这是进行“依赖注入”的最低要求。您不需要花哨的框架来为您进行注入。相反,在您的应用程序中,您分配NSManagedObjectContext
可能使用 SQLite 存储的常用实例。在您的测试中,您创建一个单独NSManagedObjectContext
的内存存储并将其传递给SomeController
. 这甚至适用于使用 OCMock 的(部分)模拟。
objc.io #4 有一些很好的例子,尤其是 Chris Eidhof 的示例应用程序: http ://www.objc.io/issue-4/full-core-data-application.html
如何访问 MOC
查看 GitHub 上的objc.io 示例代码,您会看到一个PersistentStack
帮助程序类,它负责为您的应用程序初始化托管对象上下文。Chris 使用抽象测试用例子类来提供测试上下文。
总体指导方针是这样的:
- 不要在整个代码中依赖单例助手类,因为很难用测试上下文替换它的上下文。这是我发现的一个特性,这是由于 XCTest 被“注入”到正在运行的应用程序代码中。网上有一些工作示例,但它们并没有达到我对 Xcode 5.1 和 XCTest 的预期。
- 相反,
NSManagedObjectContext
在适当的时候准备一次。传递托管对象并使用托管对象来访问上下文。
弗洛里安·库格勒这样说:
托管对象应该在应用程序中传递,至少跨越模型控制器屏障,甚至可能跨越控制器视图屏障。后者虽然更具争议性,并且可以通过例如定义对象必须符合的协议以被特定视图消费,或者通过在视图类别中实现弥合差距的配置方法来以更好的方式进行抽象从模型对象到视图的细节。
无论如何,我们不应该将托管对象限制在模型层,并在我们想要传递它们时立即将它们的数据提取到不同的结构中。托管对象是 Core Data 应用程序中的一等公民,我们应该相应地使用它们。例如,托管对象应该在视图控制器之间传递,以便为它们提供所需的数据。
为了访问托管对象上下文,我们经常在视图控制器中看到这样的代码:
NSManagedObjectContext *context =
[(MyApplicationDelegate *)[[UIApplication sharedApplication] delegate] managedObjectContext];
如果您已经将模型对象传递给视图控制器,最好通过此对象直接访问上下文:
NSManagedObjectContext *context = self.myObject.managedObjectContext;
这消除了对应用程序委托的隐藏依赖,使其更具可读性并且更易于测试。
这是我得到的最好的整体建议。现在我可以在需要的地方测试 Core Data 的使用。以前,通过全局单例类(自定义类或应用程序委托)访问上下文在生产中使用起来很方便,但在测试中证明很难验证。