尝试使用依赖注入设置核心数据堆栈
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 原则适用 :) 聪明是坏事。以上是关于尝试使用依赖注入设置核心数据堆栈的主要内容,如果未能解决你的问题,请参考以下文章
IOC 控制反转Android 事件依赖注入 ( 事件三要素 | 修饰注解的注解 | 事件依赖注入步骤 )
IOC 控制反转Android 事件依赖注入 ( 事件依赖注入具体的操作细节 | 获取要注入事件的 View 对象 | 通过反射获取 View 组件的事件设置方法 )