Как создать экземпляр UIHostingController с помощью 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 ВЫВОДИТЬ правильный / подходящий тип?

То, что я пробовал до сих пор.

5 let contentView = MyCoreDataView()

Компилирует / запускает, но не включает CoreData.

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

Компилируется, но вылетает при создании экземпляра.

Не удалось привести значение типа SwiftUI.ModifiedContent> (...) к MyHostingController.MyCoreDataView (...).

... или это просто невозможно? (пока что)

2 ответа

Решение

Вот самый быстрый приходят в ум решение - просто использоватьAnyView шрифт-ластик.

Примечание: любой модификатор представления создает (может вообще создавать) разные типы представления, поэтому в вашем случае компилятор жалуется - типы разные.

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 Dev:

Как видите, модификаторы для SwiftUI View возвращают какой-то непрозрачный тип some View, который не раскрывается программистам, но компилятор Swift утверждает, что тип везде соответствует типу...

Одно из возможных решений - создать оболочку View:

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

Я не уверен, работает ли это в вашем случае, но попробуйте.

Другие вопросы по тегам