尝试使用依赖注入设置核心数据堆栈

Posted

技术标签:

【中文标题】尝试使用依赖注入设置核心数据堆栈【英文标题】:Trying to setup Core Data stack using Dependency Injection 【发布时间】:2018-02-11 07:15:35 【问题描述】:

我现在正在做一个使用 Core Data 的项目。但是,RootViewController 不使用它。我的应用程序中的第一个 ViewController 是注册或登录屏幕。只有在用户注册或登录后,他们才会被带到需要核心数据(因此需要 ManagedObjectContext)的应用程序的初始屏幕。我想使用的核心数据堆栈如下:

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate 
    var persistentContainer: NSPersistentContainer!
    var window: UIWindow?

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool 
        createContainer  container in
            self.persistentContainer = container
            let storyboard = self.window?.rootViewController?.storyboard
            guard let vc = storyboard?.instantiateViewController(withIdentifier: "RootViewController") as? RootViewController
                else  fatalError("Cannot instantiate root view controller") 
            vc.managedObjectContext = container.viewContext
            self.window?.rootViewController = vc
        
        return true
    

    func createContainer(completion: @escaping (NSPersistentContainer) -> ()) 
        let container = NSPersistentContainer(name: "MyDataModel")
        container.loadPersistentStores  _, error in
           guard error == nil else  fatalError("Failed to load store: \(error)") 
           DispatchQueue.main.async  completion(container) 
        
    


我的问题是,我如何设置我的核心数据堆栈,并通过依赖注入绕过负责登录/注册的第一个视图控制器,并将 ManagedObjectContext 的值分配给 ViewController 的属性需要它(即 UITableViewController)?另外请记住,我没有使用情节提要,因此也需要修改上述方法以消除它的使用。

【问题讨论】:

我假设您的意思是说您正在为 NSManagedObjects 使用依赖注入,以下是为什么这不是一种流行的做事方式的几个原因:***.com/questions/43187929/… 而不是更喜欢延迟实例化的核心处理核心数据操作的数据单例类。这样想,当你可以为你的 NSManagedObject 写一个扩展来满足依赖时,你为什么要使用 DI。你应该尽量避免对你的 NSManagedObject 的任何外部依赖。 将所有这些想法投入到配置 Core Data 中的意义何在,而不是 99.9% 的所有其他应用程序都这样做?只需在 App Delegate 中创建它并使用它配置第一个 View Controller。如果第一个 VC 不想使用它,它也不必。 单例很糟糕,并且会创建难以维护的紧密耦合代码,几乎不可能测试并且很难重构。依赖注入解决了这些问题。延迟加载 Core Data 会导致性能下降。 这在 Apple 的核心数据文档中有所介绍:developer.apple.com/documentation/coredata/... "将持久容器引用传递给视图控制器在应用程序的根视图控制器中,导入核心数据并创建一个变量来保存对持久容器的引用。返回到应用程序的委托。在 application(_:didFinishLaunchingWithOptions:) 中,将应用程序窗口的 rootViewController 向下转换为应用程序的根视图控制器类型。在此引用中,设置根视图控制器的容器属性到持久化容器。” 【参考方案1】:
    应用委托应将上下文(或上下文的容器)注入根视图控制器。 根视图控制器应将上下文注入其子视图。

即使根视图控制器不使用上下文并不意味着它不能负责依赖注入。

我会直接通过根视图控制器传递容器。

【讨论】:

这意味着如果 rootViewController 是 UINavigationController 或 UITabBarController ,那么我们必须对它们进行子类化并在它们中添加上下文属性。对吗? @AkshitZaveri 通常没有。我通常会编写逻辑来查找这两种情况,当发现它们时询问它们的根或视图控制器数组,然后将 MOC 传递到下一个级别。无需为那个用例子类化。 这也是个好主意。因此,每个 UIViewController 实例都有一个 context 属性,然后可以将其传递给 ViewModels 以使用 CoreData API。 好吧,我不会用枪指着我的头的视图模型,但你知道一般的想法是的:) 视图控制器处理生命周期,视图处理显示,数据模型处理数据,其他任何东西进入适当的控制器(业务、网络等),依赖注入将所有东西绑定在一起。 KISS 原则适用 :) 聪明是坏事。

以上是关于尝试使用依赖注入设置核心数据堆栈的主要内容,如果未能解决你的问题,请参考以下文章

Spring框架依赖注入

.Net 核心依赖注入 IdbConnection

IOC 控制反转Android 事件依赖注入 ( 事件三要素 | 修饰注解的注解 | 事件依赖注入步骤 )

IOC 控制反转Android 事件依赖注入 ( 事件依赖注入具体的操作细节 | 获取要注入事件的 View 对象 | 通过反射获取 View 组件的事件设置方法 )

使用 get_it 的 Flutter 依赖注入设置问题

非控制器的网络核心依赖注入