1

I am working on implementing CoreData/Cloudkit in my project. It is built in SwiftUI using the MVVM architecture. I am stuck on the part where I am saving/adding something to CoreData, in the Xcode template provided by Apple, this is done in the ContentView file, however to me this feels like something that should be done in the ViewModel. Is that correct?

For additional context, my project is a simple game and the score is calculated in the viewModel. The score is then immediately displayed to the user through the ContentView. I also want to be able to save the score to a Leaderboard CoreData object. Since most of the work done with the score is done in the viewModel, it makes most sense to me for the saving to be handled there instead of in the view.

The template does the saving through the following code

let newItem = Item(context: viewContext)
            newItem.timestamp = Date()

            do {
                try viewContext.save()

where viewContext is @Environment(\.managedObjectContext) private var viewContext

How would I go about doing this in the ViewModel since I believe @Enviroment is for SwiftUI.

4
  • 1
    That is most likely correct but this is a very vague question. Commented Dec 12, 2021 at 21:17
  • @JoakimDanielson I tried to elaborate more and add more detail. Pls let me know if that helps or if there is anything else I should add. Commented Dec 12, 2021 at 21:23
  • Here is one approach. Not exactly what you are looking of but you can see the setup of a Manger that would be referenced by the view models Commented Dec 12, 2021 at 21:39
  • I would not take the MVVM concept too far in this case. Saving really is a function of the PersistanceController. Otherwise, as you end up with more view models, you are simply duplicating code. Commented Dec 12, 2021 at 22:19

1 Answer 1

5

I followed a tutorial by SwiftfullThinking and I think his explanation and implementation is great.

So ViewModel is also the PersistenceController:

class ViewModel: ObservableObject {

let container: NSPersistentContainer

@Published var savedData: [Entity] = []

init() {
    container = NSPersistentContainer(name: "DataContainer") //exactname of the CoreData file
    container.loadPersistentStores { (description, error) in
        if let error = error {
            fatalError("Error: \(error.localizedDescription)")
        }
    }
}

func getData() {
    let request = NSFetchRequest<TargetEntity>(entityName: "Entity") //exact name as in the CoreData file
    
    do {
        try savedData = container.viewContext.fetch(request)
    } catch {
        print("Error getting data. \(error.localizedDescription)")
    }
    
    
}

func addData(dataToSave: String) {
    let newEntity = Entity(context: container.viewContext)
    newEntity.data = dataToSave
    saveData()
}

func saveData() {
    do {
        try container.viewContext.save()
        getData() //to update the published variable to reflect this change
    } catch let error {
        print("Error: \(error)")
    }
}

Let me know if you have questions about this.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.