ronaparte
ronaparte

Reputation: 90

SwiftUI: How to pass NSManagedObjectContext into several viewmodels

I'm trying to inject my core data viewcontext into several view models, so I don't need to pass one big view model throughout the whole app.

I'm using the SwiftUI lifecycle, so the NSManagedObjectContext is generated here:

@main
struct Core_Data_VM_TestApp: App {
    let persistenceController = PersistenceController.shared

    var body: some Scene {
        WindowGroup {
            ContentView()
                .environment(\.managedObjectContext, persistenceController.container.viewContext)
        }
    }
}

Following along this answer I didn't succeed, also after playing along with different initializers.

What I want to do is something like this, which isn't working ('Cannot use instance member 'viewContext' within property initializer; property initializers run before 'self' is available')

Content View

struct ContentView: View {
    @Environment(\.managedObjectContext) private var viewContext
    @StateObject var itemVM = ItemViewModel(viewContext: viewContext)

(...)
    

Viewmodel:

class ItemViewModel: ObservableObject {
    
    var viewContext: NSManagedObjectContext
    
    init(viewContext: NSManagedObjectContext) {
        self.viewContext = viewContext
    }


}

Thanks for any help!

Upvotes: 0

Views: 1108

Answers (2)

lorem ipsum
lorem ipsum

Reputation: 29309

Just get it from your controller. The variable in the ViewModel will look something like

var viewContext: NSManagedObjectContext = PersistenceController.shared.container.viewContext

There is no need to pass it in the init.

Also, as a best practice if several anything are using something you should create an object for that something and put the common code there.

All the ViewModels can reference this single object. It will make changing things and debugging a million times easier as you app grows.

Upvotes: 2

ScottM
ScottM

Reputation: 10422

One approach is to not instantiate the @StateObject in the declaration, but in the view's init method. Note that the StateObject struct that wraps the itemVM property is stored as _itemVM:

struct ContentView: View {
  @Environment(\.managedObjectContext) private var viewContext
  @StateObject var itemVM: ItemViewModel

  init() {
    _itemVM = StateObject(wrappedValue: ItemViewModel(viewContext: viewContext))
  }
  // ...
}

Upvotes: 0

Related Questions