Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to pass/get Core Data context in SwiftUI MVVM ViewModel?

Context

To performance operation on the Core Data object, the managed object context managedObjectContext is needed. The context is passed into View via the environment variable inside SceneDelegate when the project is generated with the "using Core Data" option checked (see below). A related question is Why does Core Data context object have to be passed via environment variable?

let contentView = MainView().environment(\.managedObjectContext, context)

However, when I try to pass the context into the View Model, it complains the following

Cannot use instance member 'context' within property initializer; property initializers run before 'self' is available

struct MainView: View {
    @Environment(\.managedObjectContext) var context
    
    // Computed property cannot be used because of the property wrapper
    @ObservedObject var viewModel = ViewModel(context: context)
}

class ViewModel: ObservableObject {
    var context: NSManagedObjectContext
}

Adding an init() to initialize the view model inside the view causes a different error which fails the build.

Failed to produce diagnostic for expression; please file a bug report

    init() {
        self.viewModel = ViewModel(context: context)
    }

Question

So how can I use / get / pass the context inside the view model? What's the better way to get a context inside the view model?

like image 344
X.Creates Avatar asked Sep 18 '20 17:09

X.Creates


People also ask

Is Mvvm good for SwiftUI?

MVVM is the new standard architecture One way or another, the way SwiftUI views work with the state very much resembles the classical MVVM (unless we introduce a more complex graph of programming entities). And well, you don't need a ViewController anymore.


1 Answers

Here is your scenario

let contentView = MainView(context: context)          // << inject
        .environment(\.managedObjectContext, context)

struct MainView: View {
    @Environment(\.managedObjectContext) var context

    @ObservedObject private var viewModel: ViewModel // << declare

    init(context: NSManagedObjectContext) {
        self.viewModel = ViewModel(context: context)   // initialize
    }
}

like image 154
Asperi Avatar answered Oct 16 '22 12:10

Asperi