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?
Defining Your Realm Object Model
Open and look at Ingredient.swift, inside the Models group.
This class defines an ingredient in the domain of PotionsMaster. Notice it’s a plain Swift class with Published properties and an id to identify each object.
This object is used inside the list of ingredients and inside the form to create or edit an ingredient. However, if you try to modify any ingredient or create a new one, you see the list doesn’t change. Even though you can bind the properties of this class to the form, you’re not yet persisting any changes.
You’ll modify this object to store it in Realm now.
Still in Ingredient.swift, begin by adding the import for RealmSwift:
import RealmSwift
and then replace the declaration of the class with the following:
class Ingredient: Object, ObjectKeyIdentifiable {
Object is a type alias to RealmSwiftObject. This is the class Realm uses to store data inside a realm. By subclassing Ingredient to it, you’re able to store this class in the database.
Like Identifiable, ObjectKeyIdentifiable is a protocol Realm uses to identify Realm objects.
Next, replace the following lines:
@Published var title = ""
@Published var notes = ""
@Published var quantity = 1
@Published var bought = false
With the following code:
@Persisted var title = ""
@Persisted var notes = ""
@Persisted var quantity = 1
@Persisted var bought = false
@Persisted is a property wrapper like Core Data’s @NSManaged. It defines properties as managed by the Realm framework, allowing it to store their value.
Realm Property Types
Although you’re still using regular Swift classes to store objects in it, Realm has a limited set of platform-independent property types because of its cross-platform nature.
You can define properties with the following types:
- Bool
- Int, Int8, Int16, Int32, Int64
- Double
- Float
- String
- Date
- Data
- Decimal128
Every property of Ingredient is declared with a default required value. But you can declare optional properties, too. To define an optional property, all you have to do is make the property optional, like any other Swift property.
Relationships
Realm also supports relationships. You can declare nested objects to create many-to-one relationships. And you can use List to create many-to-many relationships. When declaring a List, Realm saves those nested objects together with your model.
Before you move on, find this code inside Ingredient.swift:
let id = UUID()
And change it to the following:
@Persisted(primaryKey: true) var id: ObjectId
This changes the ID from UUID to ObjectId and uses the Persisted(primaryKey:) to set this value as the primary key of this object. The framework uses this property to enforce uniqueness of objects and to fetch objects from Realm.
Now that you’ve defined your Realm object, it’s time to write code to fetch and add objects to your database.
Fetching Realm Objects
Fetching objects from Realm is simple. You can instantiate a realm and fetch objects from it. However, the Realm team created handy property wrappers, which are like Core Data’s FetchRequest, to use Realm with SwiftUI.
You’ll use them to fetch objects from Realm and observe changes to the database to update the view whenever you add, edit or delete an object from Realm.
Inside Views, open IngredientListView.swift. Add the RealmSwift import:
import RealmSwift
and find the following two State properties:
@State var ingredients: [Ingredient] = []
@State var boughtIngredients: [Ingredient] = []
Replace them with the following:
// 1
@ObservedResults(
// 2
Ingredient.self,
// 3
where: { $0.bought == false }
) var ingredients
// 4
@ObservedResults(
Ingredient.self,
where: { $0.bought == true }
) var boughtIngredients
Here’s a breakdown of the code:
- You define a property,
ingredients, and mark it with@ObservedResults. - The first parameter of
@ObservedResultsis the type of the object you want to fetch from Realm: in this case,Ingredient. - You also use a
whereclosure argument to filter for only the ingredients that haven’t been bought. - Here, you define another property,
boughtIngredients, and also mark it with@ObservedResults. However, this time, you filter the ingredients that have been bought.
However, it’s often better to use the where form of object filtering, because that tells the Swift compiler to check that the bought property of
filter argument calling style that takes an NSPredicate to filter your objects like Core Data does. For example:
@ObservedResults( Ingredient.self, filter: NSPredicate(format: "bought == true") ) var boughtIngredients
However, it’s often better to use the where form of object filtering, because that tells the Swift compiler to check that the bought property of
@ObservedResults( Ingredient.self, filter: NSPredicate(format: "bought == true") ) var boughtIngredients
Understanding @ObservedResults
@ObservedResults is a property wrapper you can use to fetch and observe objects from a realm. This property fetches objects and returns a Results type, which is a type from Realm that represents a collection of objects retrieved from queries.
By replacing both arrays in your view and adding those two properties, you’re telling Realm to fetch ingredients from the database and display them in the view. And you can even filter the results, just like you’re doing with the bought ingredients.
This is a powerful property wrapper. Whenever you add or remove objects that are ingredients in the database, Realm updates those properties and SwiftUI updates its views.
Before you move on, open ContentView.swift and replace the code inside NavigationView with the following:
IngredientListView()
This instantiates an IngredientListView without passing any values to the properties.
Build and run the project.

You’re not seeing the mocked data anymore and the list is gone. That’s because the database is empty and there’s nothing to list. It’s time to populate the database with objects.