CoreData with SwiftUI

This time, I will tell you about one of the oldest framework, CoreData. It was announced in iOS 3. But now we will look into it by using SwiftUI which is announced with iOS 13 at first. There are also new APIs and other frameworks to help us to manage between communications.

CoreData is capable of sorting and filtering data, and can work with much larger data. It's using DataModel which has the file extension xcdatamodeld.

After setting up your type and variable names, we can proceed to the second step of setting up Core Data: writing a little Swift code to load that model and prepare it for us to use.

We’ll start by creating a new class called DataController, making it conform to ObservableObject so that we can use it with the @StateObject property wrapper.

We want to create one of these when our app launches, then keep it alive for as long as our app runs.

import Foundation
import CoreData

class DataController: ObservableObject {
    let container = NSPersistentContainer(name: "Employee")
}

It's just preparing CoreData to load data.

To actually load the data model we need to call loadPersistentStores() on our container, which tells Core Data to access our saved data according to the data model in Employee.xcdatamodeld.

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

Final step is to create an instance of DataController and send it into SwiftUI’s environment. @Environment also stores other useful data such as our time zone, user interface appearance, and more.

@StateObject private var dataController = DataController()

We can place it into SwiftUI’s environment by adding a new modifier to the ContentView() line:

WindowGroup {
    ContentView()
        .environment(\.managedObjectContext, dataController.container.viewContext)
}

If you also want to use Xcode’s SwiftUI previews, don't forget to inject a managed object context into your preview struct for ContentView.

We need to make sure that this fetch request stays up to date over time, so that as employees are created or removed our UI stays synchronized.

There is another property wrapper. It’s called @FetchRequest and it takes at least one parameter describing how we want the results to be sorted. It has quite a specific format, so let’s start by adding a fetch request for our employees.

@FetchRequest(sortDescriptors: []) var employees: FetchedResults<Employee>

Then add this one to your ContentView:

@Environment(\.managedObjectContext) var moc

You can also create a new item from that part by using an Employee struct:

let employee = Employee(context: moc)
employee.id = UUID()
employee.name = "\(chosenFirstName) \(chosenLastName)"

After that, we need to ask our managed object context to save itself, which means it will write its changes to the persistent store.

try? moc.save()

Thanks for reading this. Stay up to date for other sharings.