如何使用 CoreData 实例化 UIHostingController?

How to Instantiate UIHostingController with CoreData?

作为一个长期的 Obj-C 开发者(自 iPhone OS 2)我决定 SwiftUI 是使用 Swift! ¯\(ツ)/¯ 因此,我仍在努力理解一种语言如何在代码中如此类型模糊,而在编译器中如此类型学究!!!

竭尽全力 Swift/SwiftUI 实例化一个 UIHostingController<>,用于 CoreData

class MyCoreDataHostingController : UIHostingController<MyCoreDataView> {

    required init?(coder: NSCoder) {//Instantiate From Storyboard
        let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
        let contentView = MyCoreDataView().environment(\.managedObjectContext, context)
        super.init(coder: coder, rootView: contentView)
        //Cannot convert value of type 'some View' to expected argument type 'MyCoreDataView'
    }
}

struct MyCoreDataView: View {
    var body: some View {
        Text("Core Data View")
    }
}

如何强制 Swift 推断 correct/appropriate 类型?

到目前为止我已经尝试了什么。

5 let contentView = MyCoreDataView()

Compiles/runs,但不包括 CoreData。

6 super.init(coder: coder, rootView: contentView as! MyCoreDataView)

编译,但在实例化时崩溃。

Could not cast value of type 'SwiftUI.ModifiedContent<MyHostingController.MyCoreDataView, SwiftUI._EnvironmentKeyWritingModifier<__C.NSManagedObjectContext>>' (...) to 'MyHostingController.MyCoreDataView' (...).

... 或者这根本不可能? (还)

这是最快的 come-in-mind 解决方案 - 只需使用 AnyView type-eraser.

注意:任何视图修饰符都会创建(通常可以创建)不同类型的视图,这就是编译器在您的情况下抱怨的原因 - 类型不同。

class MyCoreDataHostingController : UIHostingController<AnyView> {

    required init?(coder: NSCoder) {//Instantiate From Storyboard
        let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
        let contentView = MyCoreDataView().environment(\.managedObjectContext, context)
        super.init(coder: coder, rootView: AnyView(contentView))
    }
}

OOPer 在 Apple 开发者论坛上发布:

如您所见,SwiftUI View returns 一些不透明类型的修饰符 一些 View 不会向程序员显示,但 Swift 编译器声称匹配每个类型到处...

一种可能的解决方案是创建包装器视图:

class MyCoreDataHostingController : UIHostingController<MyCoreDataViewEnvironmentWrapper> {
    required init?(coder: NSCoder) {//Instantiate From Storyboard
        let contentView = MyCoreDataViewEnvironmentWrapper()
        super.init(coder: coder, rootView: contentView)
    }
}
struct MyCoreDataViewEnvironmentWrapper: View {
    private let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
    
    var body: some View {
        MyCoreDataView().environment(\.managedObjectContext, context)
    }
}

或者您可以选择 AnyView 作为包装器:

class MyCoreDataHostingController : UIHostingController<AnyView> {
    required init?(coder: NSCoder) {//Instantiate From Storyboard
        let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
        let contentView = AnyView(MyCoreDataView().environment(\.managedObjectContext, context))
        super.init(coder: coder, rootView: contentView)
    }
}

我不确定这是否适用于您的情况,但请尝试。