swiftswiftuiswiftdataswift-data-modelcontext

How to create environment objects in SwiftData


In a UIKit-based app where I'm integrating SwiftUI:

class SwiftDataManager {
    static let shared = SwiftDataManager()
    private init() {}

    var container: ModelContainer?

    func initializeContainer() {
        
        do {
            container = try ModelContainer(for: Cat.self, Dog.self)
            
        } catch {
            fatalError("Could not create ModelContainer: \(error)")
        }
        
    }
}

struct SomeView: View {
    @Environment(\.modelContext) var modelContext
    ...
    //list cats and dogs
}

let vc = UIHostingController(rootView: SomeView().environmentObject(SwiftDataManager.shared.container?.mainContext))
vc.modalPresentationStyle = .fullScreen
present(vc, animated: true, completion: nil)

Error on the environmentObject line:

Instance method 'environmentObject' requires that 'ModelContext' conform to 'ObservableObject'

How do I get the modelContext into SomeView so that I can work with the objects saved in SwiftData?


Solution

  • Notice how you read the model context in a SwiftUI view:

    @Environment(\.modelContext) var modelContext
    

    You use the overload of @Environment that takes an EnvironmentValues key path. You do not use @EnvironmentObject to access the model context, do you?

    So in the same way, you use the .environment modifier that takes an EnvironmentValues key path to set the model context.

    UIHostingController(rootView: Group {
        if let container = SwiftDataManager.shared.container {
            SomeView().environment(\.modelContext, container.mainContext)
        }
        // else { SomeView() } perhaps?
    })
    

    I'm not sure why your container here is optional. You should decide what to do when it is nil.