Quick Start - Swift SDK
On this page
This Quick Start demonstrates how to use Realm with the Realm Swift SDK. Before you begin, ensure you have Installed the Swift SDK.
Tip
See also:
If your app uses SwiftUI, check out the SwiftUI Quick Start.
Import Realm
Near the top of any Swift file that uses Realm, add the following import statement:
import RealmSwift
Define Your Object Model
For a local-only realm, you can define your object model directly in code. In this quick start, you can remove
ownerId
unless you want to add the optional Device Sync.
class Todo: Object { true) var _id: ObjectId (primaryKey: var name: String = "" var status: String = "" var ownerId: String convenience init(name: String, ownerId: String) { self.init() self.name = name self.ownerId = ownerId } }
Open a Realm
In a local-only realm, the simplest option to open a realm is to use the default realm with no configuration parameter:
// Open the local-only default realm let realm = try! Realm()
You can also specify a Realm.Configuration parameter to open a realm at a specific file URL, in-memory, or with a subset of classes.
For more information, see: Configure and Open a Realm.
Create, Read, Update, and Delete Objects
Once you have opened a realm, you can modify it and its objects in a write transaction block.
To create a new Todo object, instantiate the Todo class and add it to the realm in a write block:
let todo = Todo(name: "Do laundry", ownerId: user.id) try! realm.write { realm.add(todo) }
You can retrieve a live collection of all todos in the realm:
// Get all todos in the realm let todos = realm.objects(Todo.self)
You can also filter that collection using where:
let todosInProgress = todos.where { $0.status == "InProgress" } print("A list of all todos in progress: \(todosInProgress)")
To modify a todo, update its properties in a write transaction block:
// All modifications to a realm must happen in a write block. let todoToUpdate = todos[0] try! realm.write { todoToUpdate.status = "InProgress" }
Finally, you can delete a todo:
// All modifications to a realm must happen in a write block. let todoToDelete = todos[0] try! realm.write { // Delete the Todo. realm.delete(todoToDelete) }
Watch for Changes
You can watch a realm, collection, or object for changes with the observe
method.
// Retain notificationToken as long as you want to observe let notificationToken = todos.observe { (changes) in switch changes { case .initial: break // Results are now populated and can be accessed without blocking the UI case .update(_, let deletions, let insertions, let modifications): // Query results have changed. print("Deleted indices: ", deletions) print("Inserted indices: ", insertions) print("Modified modifications: ", modifications) case .error(let error): // An error occurred while opening the Realm file on the background worker thread fatalError("\(error)") } }
Be sure to retain the notification token returned by observe
as
long as you want to continue observing. When you are done observing,
invalidate the token to free the resources:
// Invalidate notification tokens when done observing notificationToken.invalidate()
Add Device Sync (Optional)
If you want to sync Realm data across devices, you can set up an Atlas App Services App and enable Device Sync. For more information on what you can do with App Services, see: App Services - Swift SDK.
Prerequisites
Before you can sync Realm data, you must:
Enable Flexible Sync with Development Mode toggled to
On
and anownerId
field in the Queryable Fields section.
Initialize the App
To use App Services features such as authentication and sync, access your App Services App using your App ID. You can find your App ID in the App Services UI.
let app = App(id: APP_ID) // Replace APP_ID with your Atlas App ID
Authenticate a User
In this quick start, you use anonymous authentication to log in users without requiring them to provide any identifying information. After authenticating the user, you can open a realm for that user.
do { let user = try await app.login(credentials: Credentials.anonymous) print("Successfully logged in user: \(user)") await openSyncedRealm(user: user) } catch { print("Error logging in: \(error.localizedDescription)") }
The Realm Swift SDK provides many additional ways to authenticate, register, and link users. For other authentication providers, see: Authenticate Users - Swift SDK
Open a Realm
Once you have enabled Device Sync and authenticated a user, you can create a Configuration object and open the realm. You can then add a the Flexible Sync subscription that determines what data the realm can read and write.
Once you have a realm with a subscription, this example passes the realm and the user to another function where you can use the realm.
Tip
If your app accesses Realm in an async/await
context, mark the code
with @MainActor
to avoid threading-related crashes.
// Opening a realm and accessing it must be done from the same thread. // Marking this function as `@MainActor` avoids threading-related issues. func openSyncedRealm(user: User) async { do { var config = user.flexibleSyncConfiguration() // Pass object types to the Flexible Sync configuration // as a temporary workaround for not being able to add a // complete schema for a Flexible Sync app. config.objectTypes = [Todo.self] let realm = try await Realm(configuration: config, downloadBeforeOpen: .always) // You must add at least one subscription to read and write from a Flexible Sync realm let subscriptions = realm.subscriptions try await subscriptions.update { subscriptions.append( QuerySubscription<Todo> { $0.ownerId == user.id }) } await useRealm(realm: realm, user: user) } catch { print("Error opening realm: \(error.localizedDescription)") } }
The syntax to read, write, and watch for changes on a synced realm is identical to the syntax for non-synced realms above. While you work with local data, a background thread efficiently integrates, uploads, and downloads changesets.
Every write transaction for a subscription set has a performance cost. If you need to make multiple updates to a Realm object during a session, consider keeping edited objects in memory until all changes are complete. This improves sync performance by only writing the complete and updated object to your realm instead of every change.