XYZ
XYZ

Reputation: 27387

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?

Upvotes: 12

Views: 6689

Answers (2)

Asperi
Asperi

Reputation: 257739

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

Upvotes: 12

XYZ
XYZ

Reputation: 27387

The CoreData context can get via the AppDelegate object.

import SwiftUI

class ViewModel: ObservableObject {
    var context: NSManagedObjectContext
    
    init() {
        let app = UIApplication.shared.delegate as! AppDelegate
        self.context = app.persistentContainer.viewContext
    }
}

REFERENCE, https://kavsoft.dev/Swift/CoreData/

Upvotes: 1

Related Questions