Realm With SwiftUI Tutorial: Getting Started
Learn how to use Realm with SwiftUI as a data persistence solution by building a potion shopping list app. By Renan Benatti Dias.
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Contents
Realm With SwiftUI Tutorial: Getting Started
30 mins
- Getting Started
- Project Structure
- Working With Realm
- Understanding the Realm Database
- Setting up Realm
- Defining Your Realm Object Model
- Realm Property Types
- Relationships
- Fetching Realm Objects
- Understanding @ObservedResults
- Adding Objects to the Database
- Updating Objects
- Toggling Ingredients to BOUGHT
- Updating Other Properties
- Deleting Objects
- Adding a New Property to a Realm Object
- Storing the New Property in Realm
- Working With Migrations
- Creating a Migration
- Updating Ingredient Row
- Where to Go From Here?
Storing the New Property in Realm
Now that you’re ready to store the new color, it’s time to update IngredientFormView.swift to let users select the ingredient color. You’ll use a Picker
view to allow users to select the color from the available options.
Open IngredientFormView.swift and add the following property:
let colorOptions = ColorOptions.allCases
This adds a property to store all cases of ColorOption
. You’ll use this to list all color options in the picker view.
Next, find the comment // To Do Add Color Picker
and replace it with the code below:
Picker("Color", selection: $ingredient.colorOption) {
ForEach(colorOptions, id: \.self) { option in
Text(option.title)
}
}
This adds a Picker
view to the form, binding the property colorOption
form to the ingredient, with all the cases from ColorOption
.
Build and run. And you get …
The app crashes as soon as you open it! Realm throws a migration error: Migration is required due to the following errors
. But why is this happening?
Working With Migrations
When your app launches, Realm scans your code for classes that subclass Object
. When it finds one, it creates a schema for mapping the model to the database.
When you change an object and add a property, there’s a mismatch between the new schema and the one in the database. If that happens, Realm throws an error. It doesn’t know what it should do with the old objects without the new property. You have to tell Realm how to migrate the old schema to the new one. Otherwise, it doesn’t know how to map old objects to the new schema.
Because you added a new property, colorOption
, to Ingredient
, you must create a migration for it.
true
to deleteRealmIfMigrationNeeded
when you instantiate Realm.Configuration
. That tells Realm that, if it needs to migrate, it should delete its file and create a new one. Another way to solve this, during development, is simply deleting the app and building and running it again. This deletes the realm on disk and creates a brand new one from scratch.
Creating a Migration
In the Models group, create a file named RealmMigrator.swift.
Now, add this code to your new file:
import RealmSwift
enum RealmMigrator {
// 1
static private func migrationBlock(
migration: Migration,
oldSchemaVersion: UInt64
) {
// 2
if oldSchemaVersion < 1 {
// 3
migration.enumerateObjects(
ofType: Ingredient.className()
) { _, newObject in
newObject?["colorOption"] = ColorOptions.green
}
}
}
}
Here's the breakdown:
- You define a migration method. The method receives a migration object and
oldSchemaVersion
. - You check the version of the file-persisted schema to decide which migration to run. Each schema has a version number, starting from zero. In this case, if the old schema is the first one (before you added a new property), run the migration.
- Finally, for each of the old and new
Ingredient
objects in Realm, you assign a default value to the new property,colorOption
.
Realm uses migrationBlock
to run the migration and update any necessary properties.
At the bottom of RealmMigrator
, add the following new static
property:
static var configuration: Realm.Configuration {
Realm.Configuration(schemaVersion: 1, migrationBlock: migrationBlock)
}
You create a new instance of Realm.Configuration
using your migrationBlock
and set the current version of the schema to 1.
You'll use this configuration with your default realm now.
Open AppMain.swift and add the following line just below ContentView
:
.environment(\.realmConfiguration, RealmMigrator.configuration)
Realm uses this configuration to open the default database. When that happens, Realm detects a mismatch between the file-persisted schema and the new schema. It then migrates the changes by running the migration function you just created.
Build and run again. This time the crash is gone!
You've added a new property to Ingredient
. And you've taken care of the migration. Now it's time to update the row so users can see the color they choose!
Updating Ingredient Row
Open Ingredient.swift and add the following extension at the bottom of the file:
extension Ingredient {
var color: Color {
colorOption.color
}
}
This adds a convenient computed property to get the color of the selected option.
Next, open IngredientRow.swift and find the following code:
Button(action: toggleBought) {
Image(systemName: buttonImage)
.resizable()
.frame(width: 24, height: 24)
}
Add the following view modifier to the image, inside the button:
.foregroundColor(ingredient.color)
Here, you change the foreground color of the icon to toggle an ingredient as bought to the color the user selects for that ingredient.
Build and run to see the changes. Now, create a new ingredient and select a color for it.
Great job! Now, you can list all the ingredients you need for that special potion you're brewing. :]
Where to Go From Here?
You can download the final project by clicking the Download Materials button at the top or bottom of the tutorial.
In this SwiftUI Realm tutorial, you learned to create, update, fetch and delete objects from Realm using SwiftUI. In addition to the basics, you also learned about migrations and how to create them.
To learn more about Realm, you can refer to its official documentation.
If you want to learn more about SwiftUI, see the book SwiftUI by Tutorials.
I hope you enjoyed this tutorial. If you have any questions or comments, please feel free to join the discussion below.