M5L3: Core Data CRUD

So, what did we learn in lesson 3 of module 5 of the CWC+ iOS Dabatases course?

Well, firstly, that Xcode creates a lot of dummy code for demonstration purposes that we don’t need to use.

More usefully, our main top-level Swift file contains these essential pieces of code:

import SwiftUI

@main
struct DemoApp: App {
    let persistenceController = PersistenceController.shared

    var body: some Scene {
        WindowGroup {
            ContentView()
                .environment(\.managedObjectContext, persistenceController.container.viewContext)
        }
    }
}

As we learned in the previous lesson, the first highlighted line creates a shared instance of the PersistenceController, and the second highlighted line allows us to access the container in sub-views as an environment value.

To fetch data, we use the following code where Person is our Core Data object:

@FetchRequest(sortDescriptors: []) var people: FetchedResults<Person>

The sortDescriptors parameter allows us to sort the data, which is something I’m sure we’ll get to in a later lesson.

Now we’re ready to Create, Retrieve, Update, and Delete items in our views.

Create Example:

private func addItem() {
    let p = Person(context: viewContext) 
    p.age = 20
    p.name = "Tom"
    do {
        try viewContext.save() // attempt to save object into core data
    }
    catch {
        // Handle potential error
    }
}

The code viewContext.save() is required to commit all changes to core data. As this has the potential to throw an error, we need to use do-catch, or just force ignore the error.

To add an item, in this example, we just make a call to our method :

Button(action: addItem) {
    Label("Add Item", systemImage: "plus")
}

Retrieve Example:

List {
    ForEach(people) { person in
        Text(person.name ?? "No name")
    }
}

Update Example:

List {
    ForEach(people) { person in
        Text(person.name ?? "No name")
            .onTapGesture{
                 person.name = "Joe"
                 try! viewContext.save()
            }
    }
}

Here, on tapping the person’s name, that name will be changed to “Joe” but it wouldn’t be committed to core data if we didn’t call viewContext.save().

Delete Example:

List {
    ForEach(people) { person in
        Text(person.name ?? "No name")
            .onTapGesture{
                viewContext.delete(person)
                try! viewContext.save()
            }
    }
}

Again, we need to call viewContext.save() to make the viewContext.delete() commit to core data.

There’s a lot of code to wade through when you first set up the project through Xcode, but I think the essentials to handle the basics look to be pretty straightforward. I’m looking forward to the next lessons when we use this in practical examples.