Core Data III
Core Data in a ViewModel.
Core Data III
Core Data in a ViewModel.
0
0
Checkbox to mark video as read
Mark as read

We explored the basics of Core Data in previous articles like this one, where the data was managed directly on the View. This is fine for managing simple data sets, but when it starts to get complicated it's recommended to manage that data from a ViewModel.

Data Model file and entity Person will be created in the same way as in the previous Core Data articles. Then we can create a Core Data manager called CoreData.

import CoreData

class CoreData {

    let container = NSPersistentContainer(name: "Model")

    static let shared = CoreData()

    private init() {
        container.loadPersistentStores { description, error in
            if let error = error {
                print("Core Data failed to load: \(error.localizedDescription)")
            }
        }
    }
}

ViewModel

The next step is to create a ViewModel. From one side, this ViewModel will store the array of Person and the inputText that the View will use to show the results, and on the other side, fetch() and addPersonTapped() will update the data using moc.

import CoreData
import SwiftUI

@Observable
class ViewModel {

    let moc = CoreData.shared.container.viewContext

    var persons: [Person] = []
    var inputText: String = ""

    func fetchData() {
        // Create NSFetchRequest instance
        let fetchRequest = NSFetchRequest(entityName: "Person")

        // Add sort descriptors
        let sortDescriptor = NSSortDescriptor(keyPath: \Person.name, ascending: true)
        fetchRequest.sortDescriptors = [sortDescriptor]

        // Add predicate (uncomment to apply a filter)
        //let predicate = NSPredicate(format: "name == %@", "Pablo")
        //fetchRequest.predicate = predicate

        // Fetch data
        do {
            persons = try moc.fetch(fetchRequest)
        } catch let error {
            print("Error fetching items: \(error.localizedDescription)")
        }
    }

    func addButtonTapped() {
        guard !inputText.isEmpty else {
            return
        }

        addPerson(name: inputText)

        inputText = ""
    }

    func addPerson(name: String) {
        var person = Person(context: moc)
        person.id = UUID()
        person.name = name

        try? moc.save()

        fetchData()
    }
}

View

The View will show the data as usual. This View will also trigger the first data fetch through onAppear() modifier.

import SwiftUI

struct ContentView: View {

    @State var viewModel = ViewModel()

    var body: some View {
        VStack {
            List(viewModel.persons) { person in
                Text(person.name ?? "No name")
            }

            inputBar
        }
        .onAppear(perform: {
            viewModel.fetchData()
        })
    }

    var inputBar: some View {
        HStack {
            TextField("", text: $viewModel.inputText)
                .textFieldStyle(.roundedBorder)

            Button {
                viewModel.addButtonTapped()
            } label: {
                Text("ADD")
            }
        }
        .padding()
    }
}

#Preview {
    ContentView()
}

Result

You can find all this code together in our samples repository, here.

0 Comments

Join the community to comment

Be the first to comment

Accept Cookies

We use cookies to collect and analyze information on site performance and usage, in order to provide you with better service.

Check our Privacy Policy