CRUD - Create - Swift SDK
On this page
- Key Concept: Transactions
- Write Transactions
- Run a Transaction
- Key Concept: Interface-Driven Writes
- Create a New Object
- About The Examples On This Page
- Create an Object
- Initialize Objects with a Value
- Create an Object with JSON
- Create an Embedded Object
- Create an Object with a Map Property
- Create an Object with a MutableSet Property
- Create an Object with an AnyRealmValue Property
- Copy an Object to Another Realm
Key Concept: Transactions
Write Transactions
Realm Database uses a highly efficient storage engine to persist objects. You can create objects in a realm, update objects in a realm, and eventually delete objects from a realm. Because these operations modify the state of the realm, we call them writes.
Realm handles writes in terms of transactions. A transaction is a list of read and write operations that Realm treats as a single indivisible operation. In other words, a transaction is all or nothing: either all of the operations in the transaction succeed or none of the operations in the transaction take effect.
All writes must happen in a transaction.
A realm allows only one open transaction at a time. Realm blocks other writes on other threads until the open transaction is complete. Consequently, there is no race condition when reading values from the realm within a transaction.
When you are done with your transaction, Realm either commits it or cancels it:
- When Realm commits a transaction, Realm writes all changes to disk. For synced realms, the SDK queues the change for synchronization with App Services.
- When Realm cancels a write transaction or an operation in the transaction causes an error, all changes are discarded (or "rolled back").
Run a Transaction
The Swift SDK represents each transaction as a callback function
that contains zero or more read and write operations. To run
a transaction, define a transaction callback and pass it to
the realm's write
method. Within this callback, you are
free to create, read, update, and delete on the realm. If
the code in the callback throws an exception when Realm runs
it, Realm cancels the transaction. Otherwise, Realm commits
the transaction immediately after the callback.
Since transactions block each other, it is best to avoid opening transactions on both the UI thread and a background thread. If you are using Sync, avoid opening transactions on the UI thread altogether, as Realm processes synchronizations on a background thread. If a background transaction blocks your UI thread's transaction, your app may appear unresponsive.
The following code shows how to run a transaction with the realm's write method. If the code in the callback throws an exception, Realm cancels the transaction. Otherwise, Realm commits the transaction.
Key Concept: Interface-Driven Writes
Realm always delivers notifications asynchronously, so they never block the UI thread. However, there are situations when the UI must reflect changes instantly. If you update the UI directly at the same time as the write, the eventual notification could double that update. This could lead to your app crashing due to inconsistent state between the UI and the backing data store. To avoid this, you can write without sending a notification to a specific handler. We call this type of transaction an interface-driven write.
Say we decide to manage a table view's data source manually, because our app design requires an instantaneous response to UI-driven table updates. As soon as a user adds an item to the table view, we insert it to our data source, which writes to the realm but also immediately kicks off the animation. However, when Realm delivers the change notification for this insertion a little later, it indicates that an object has been added. But we already updated the table view for it! Rather than writing complicated code to handle this case, we can use interface-driven writes to prevent a specific notification handler from firing for that specific write.
Interface-driven writes, also known as silent writes, are especially useful when using fine-grained collection notifications with a synchronized realm realm. While you use interface-driven writes for the current user's updates and update the UI immediately, the sync process can use standard notifications to update the UI.
Create a New Object
About The Examples On This Page
The examples on this page use the following models:
Create an Object
Initialize Objects with a Value
You can initialize an object by passing an initializer value to Object.init(value:). The initializer value can be a key-value coding compliant object, a dictionary, or an array containing one element for each managed property.
When using an array as an initializer value, you must include all properties in the same order as they are defined in the model.
You can even initialize related or embedded objects by nesting initializer values:
Some Property Types are Only Mutable in a Write Transaction
Some property types are only mutable in a write transaction. For example, you can instantiate an object with a MutableSet property, but you can only set that property's value in a write transaction. You cannot initialize the object with a value for that property unless you do so inside a write transaction.
Create an Object with JSON
Realm does not directly support JSON, but you can use JSONSerialization.jsonObject(with:options:) to convert JSON into a value that you can pass to Realm.create(_:value:update:).
Nested objects or arrays in the JSON map to to-one or to-many relationships.
The JSON property names and types must match the destination object schema exactly. For example:
float
properties must be initialized with float-backedNSNumbers
.Date
andData
properties cannot be inferred from strings. Convert them to the appropriate type before passing to Realm.create(_:value:update:).- Required properties cannot be
null
or missing in the JSON.
Realm ignores any properties in the JSON not defined in the object schema.
If your JSON schema doesn't exactly align with your Realm objects, consider using a third-party framework to transform your JSON. There are many model mapping frameworks that work with Realm. See a partial list in the realm-swift repository.
Create an Embedded Object
To create an embedded object, assign an instance of the embedded object to a parent object's property:
Create an Object with a Map Property
When you create an object that has a map property, you can set the values for keys in a few ways:
- Set keys and values on the object and then add the object to the realm
- Set the object's keys and values directly inside a write transaction
- Use key-value coding to set or update keys and values inside a write transaction
let realm = try! Realm() // Record a dog's name and current city let dog = Dog() dog.name = "Wolfie" dog.currentCity = "New York" // Set map values dog.favoriteParksByCity["New York"] = "Domino Park" // Store the data in a realm try! realm.write { realm.add(dog) // You can also set map values inside a write transaction dog.favoriteParksByCity["Chicago"] = "Wiggly Field" dog.favoriteParksByCity.setValue("Bush Park", forKey: "Ottawa") }
Create an Object with a MutableSet Property
You can create objects that contain MutableSet properties as you would any Realm object, but you can only mutate a MutableSet within a write transaction. This means you can only set the value(s) of a mutable set property within a write transaction.
let realm = try! Realm() // Record a dog's name and current city let dog = Dog() dog.name = "Maui" dog.currentCity = "New York" // Store the data in a realm. Add the dog's current city // to the citiesVisited MutableSet try! realm.write { realm.add(dog) // You can only mutate the MutableSet in a write transaction. // This means you can't set values at initialization, but must do it during a write. dog.citiesVisited.insert(dog.currentCity) } // You can also add multiple items to the set. try! realm.write { dog.citiesVisited.insert(objectsIn: ["Boston", "Chicago"]) } print("\(dog.name) has visited: \(dog.citiesVisited)")
Create an Object with an AnyRealmValue Property
When you create an object with an AnyRealmValue property, you must specify the type of the value you store in the property. The Realm Swift SDK provides an AnyRealmValue enum that iterates through all of the types the AnyRealmValue can store.
Later, when you read an AnyRealmValue, you must check the type before you do anything with the value.
// Create a Dog object and then set its properties let myDog = Dog() myDog.name = "Rex" // This dog has no companion. // You can set the field's type to "none", which represents `nil` myDog.companion = .none // Create another Dog whose companion is a cat. // We don't have a Cat object, so we'll use a string to describe the companion. let theirDog = Dog() theirDog.name = "Wolfie" theirDog.companion = .string("Fluffy the Cat") // Another dog might have a dog as a companion. // We do have an object that can represent that, so we can specify the // type is a Dog object, and even set the object's value. let anotherDog = Dog() anotherDog.name = "Fido" // Note: this sets Spot as a companion of Fido, but does not set // Fido as a companion of Spot. Spot has no companion in this instance. anotherDog.companion = .object(Dog(value: ["name": "Spot"])) // Add the dogs to the realm let realm = try! Realm() try! realm.write { realm.add([myDog, theirDog, anotherDog]) } // After adding these dogs to the realm, we now have 4 dog objects. let dogs = realm.objects(Dog.self) XCTAssertEqual(dogs.count, 4)
Copy an Object to Another Realm
The create
methods do not support handling cyclical object
graphs. Do not pass in an object containing relationships involving
objects that refer back to their parents, either directly or
indirectly.