Search code examples
iosswiftcore-dataswiftuiuihostingcontroller

How to Instantiate UIHostingController with CoreData?


As a long-time Obj-C dev (since iPhone OS 2) I decided that SwiftUI was the nudge to use Swift! ¯\(ツ)/¯ Thus, I am still trying to understand how a language can be so type-vague in code, and so type-pedantic in the compiler!!!

Pulling my hair out trying to get Swift/SwiftUI to instantiate a UIHostingController<>, for use with 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")
    }
}

How can I FORCE Swift to INFER the correct/appropriate type?

What I have tried so far.

5 let contentView = MyCoreDataView()

Compiles/runs, but does not include CoreData.

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

Compiles, but crashes at instantiation.

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

... or is this simply not possible? (yet)


Solution

  • Here is the fastest come-in-mind solution - just use AnyView type-eraser.

    Note: any view modifier creates (can create in general) different type of view, that's why compiler complains in your case - types are different.

    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))
        }
    }