Data Persistence in SwiftUI

Jun 20 2024 · Swift 5.9, iOS 17.2, Xcode 15.1

Lesson 03: Persisting Data with SwiftData

Demo

Episode complete

Play next episode

Next
Transcript

Open the starter project for this lesson; you’ll find the familiar JoyJotter app from the previous lessons. However, take a moment to notice a new addition: the Jokes Authors tab. Here, you’ll discover a list of authors along with their corresponding countries. Dive into the details by selecting an author, where you can seamlessly edit their name or country and save your changes. This model will be the main focus of your adventure as you use SwiftData to save and work with it. It’s time to start your journey to improve the JoyJotter app with SwiftData.

Configuring SwiftData Model

Open JokeAuthorModel. You’ll find the JokeAuthor model. Import the SwiftData library to this file; then, you’ll convert this model to a SwiftData model by adding the @Model macro. Then, add the @Attribute(.unique) property wrapper to the id property to make it unique all over the instances of this model.

@Model
class JokeAuthor: Identifiable {
  @Attribute(.unique) var id = UUID()
  var name: String
  var country: String

  init(id: UUID = UUID(), name: String = "", country: String = "") {
    self.id = id
    self.name = name
    self.country = country
  }
}

Next, open AppMain, where you’ll find the top level of your view hierarchy, which is the ContentView. Now, import the SwiftData library, then add the modelContainer property. Next, initialize the modelContainer with the JokeAuthor model inside the initializer of the AppMain.

let modelContainer: ModelContainer

init() {
  do {
    modelContainer = try ModelContainer(for: JokeAuthor.self)
  } catch {
    fatalError("Could not initialize ModelContainer")
  }
}

Finally, add the modelContainer to the ContentView. This will tell SwiftData to persist this model in runtime.

.modelContainer(for: modelContainer)

SwiftData can now deal with the JokeAuthor model anywhere in your code. It’s time to start reading and creating data using this model.

SwiftData CRUD Operations

Reading

Open JokeAuthorsListView, and import the SwiftData library to it. Then, replace the jokeAuthors property with the one provided with the Query property wrapper. You can sort it according to country and sort it ascending using the parameters of the Query property wrapper.

@Query(sort: \JokeAuthor.country, order: .forward) var jokeAuthors: [JokeAuthor]

Using this property in your list means you’re now using data retrieved from SwiftData storage instead of the default list you had before. Suppress the errors for now in this file by commenting out the different parts in your code. Build and run your app, then go to the Jokes Authors tab. You’ll see it’s currently empty because it fetched data from SwiftData for this model.

Creating

Open AddAuthorView. It’s the view responsible for adding new jokes. Import the SwiftData library into it, then add the context environment property to it. This one will help you create new instances of your model, as you learned in the previous section.

@Environment(\.modelContext) private var context

Next, remove the jokeAuthors property and replace the jokeAuthors.append(newAuthor) with context.insert(newAuthor). This lets you add new instances in SwiftData storage when you press save on this screen. Remove jokeAuthors property from the initializer inside your preview.

Finally, open JokeAuthorsListView and uncomment the code for the AddAuthorView. Make sure to remove the extra jokeAuthor property. Build and run your app. Then, navigate to the Jokes Authors tab. Press the plus button, add a new author, and then press save. Notice how this new author is added to your list.

Stop and restart your app. Observe how this author continues to appear in your list. This is because of the persistence you established using SwiftData. Now, you’ll take care of the updating process.

Updating

Open EditAuthorView. Remove the authorName, authorCountry, and jokeAuthors properties. Replace selectedAuthor property with new Bindable author property. You’ll pass the author to be edited from the JokeAuthorsListView to this property.

@Bindable var author: JokeAuthor

Next, bind the new author property to the text fields to show and edit the author name and country in two way binding.

TextField("Author Name", text: $author.name)
TextField("Country", text: $author.country)

Now, remove the onAppear and updateAuthor methods totally as you won’t need them both now. Next, replace the action for the Save button to only dismiss the screen. Edit the initializer inside the preview to fix the current error.

presentationMode.wrappedValue.dismiss()

Finally, open JokeAuthorsListView and replace the code for the EditAuthorView with the new initializer.

EditAuthorView(
  author: author
)

Build and run the app. Go to the author’s details, make changes to their name or country, then stop and restart your app again. See how the updates are also saved effortlessly thanks to the automatic update feature of the Query property wrapper.

Deleting

The final CRUD operation that you’ll add to your model is the deleting part. Open JokeAuthorsListView. Then add the context environment property to it.

@Environment(\.modelContext) private var context

Next, replace the code in the onDelete method with the delete method for the context property.

for index in indexSet {
  let author = jokeAuthors[index]
  context.delete(author)
}

This piece of code removes the author from your storage when you swipe to delete it in this view. Build and run your app, then swipe to delete the author. This action will empty the list. Stop and restart your app, and see how the list remains empty, confirming the successful deletion.

Congratulations! You’ve now completed the CRUD operations for your model using SwiftData. Well done!

See forum comments
Cinema mode Download course materials from Github
Previous: Instruction Next: Conclusion