Reputation: 395
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)
Upvotes: 3
Views: 454
Reputation: 395
Posted by OOPer on Apple Dev Forums:
As you see, modifiers for SwiftUI View returns some opaque type some View which is not revealed to programmers but Swift compiler claims matching the type every here and there...
One possible solution is creating a wrapper 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)
}
}
Or you can choose AnyView as the wrapper:
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)
}
}
I'm not sure if this works for your case, but please try.
Upvotes: 0
Reputation: 257663
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))
}
}
Upvotes: 2