React to Changes - Swift SDK
On this page
- Register a Realm Change Listener
- Register a Collection Change Listener
- Register an Object Change Listener
- Register a Key Path Change Listener
- Realm Collections
- Write Silently
- Stop Watching for Changes
- Key-value Observation
- Key-value Observation Compliance
- Managed vs. Unmanaged KVO Considerations
- Observing Realm Lists
Register a Realm Change Listener
You can register a notification handler on an entire realm. Realm Database calls the notification handler whenever any write transaction involving that Realm is committed. The handler receives no information about the change.
Register a Collection Change Listener
You can register a notification handler on a collection within a realm.
Realm Database notifies your handler:
- After first retrieving the collection.
- Whenever a write transaction adds, changes, or removes objects in the collection.
Notifications describe the changes since the prior notification with three lists of indices: the indices of the objects that were deleted, inserted, and modified.
In collection notification handlers, always apply changes in the following order: deletions, insertions, then modifications. Handling insertions before deletions may result in unexpected behavior.
Collection notifications provide a change
parameter that reports which
objects are deleted, added, or modified during the write transaction. This
RealmCollectionChange
resolves to an array of index paths that you can pass to a UITableView
's
batch update methods.
Register an Object Change Listener
You can register a notification handler on a specific object within a Realm. Realm Database notifies your handler:
- When the object is deleted.
- When any of the object's properties change.
The handler receives information about what fields changed and whether the object was deleted.
Register a Key Path Change Listener
New in version 10.12.0.
In addition to registering a notification handler on an object
or collection, you can pass an optional string keyPaths
parameter to specify the key path or
key paths to watch.
// Define the dog class. class Dog: Object { var name = "" var favoriteToy = "" var age: Int? } var objectNotificationToken: NotificationToken? func objectNotificationExample() { let dog = Dog() dog.name = "Max" dog.favoriteToy = "Ball" dog.age = 2 // Open the default realm. let realm = try! Realm() try! realm.write { realm.add(dog) } // Observe notifications on some of the object's key paths. Keep a strong // reference to the notification token or the observation will stop. // Invalidate the token when done observing. objectNotificationToken = dog.observe(keyPaths: ["favoriteToy", "age"], { change in switch change { case .change(let object, let properties): for property in properties { print("Property '\(property.name)' of object \(object) changed to '\(property.newValue!)'") } case .error(let error): print("An error occurred: \(error)") case .deleted: print("The object was deleted.") } }) // Now update to trigger the notification try! realm.write { dog.favoriteToy = "Frisbee" } // When you specify one or more key paths, changes to other properties // do not trigger notifications. In this example, changing the "name" // property does not trigger a notification. try! realm.write { dog.name = "Maxamillion" } }
New in version 10.14.0.
You can observe a partially type-erased PartialKeyPath on Objects or RealmCollections.
objectNotificationToken = dog.observe(keyPaths: [\Dog.favoriteToy, \Dog.age], { change in
When you specify keyPaths
, only changes to those
keyPaths
trigger notification blocks. Any other changes do not trigger
notification blocks.
Consider a Dog
object where one of its properties is a list of
siblings
:
class Dog: Object { var name = "" var siblings: List<Dog> var age: Int? }
If you pass siblings
as a keyPath
to observe, any insertion,
deletion, or modification to the siblings
list would trigger a
notification. However, a change to someSibling.name
would not trigger
a notification, unless you explicitly observed ["siblings.name"]
.
Multiple notification tokens on the same object which filter for separate key paths do not filter exclusively. If one key path change is satisfied for one notification token, then all notification token blocks for that object will execute.
Realm Collections
When you observe key paths on the various collection types, expect these behaviors:
- LinkingObjects:: Observing a property of the LinkingObject triggers a notification for a change to that property, but does not trigger notifications for changes to its other properties. Insertions or deletions to the list or the object that the list is on trigger a notification.
- Lists: Observing a property of the list's object will triggers a notification for a change to that property, but does not trigger notifications for changes to its other properties. Insertions or deletions to the list or the object that the list is on trigger a notification.
- Map:
Observing a property of the map's object triggers a notification for a change
to that property, but does not trigger notifications for changes to its other
properties. Insertions or deletions to the Map or the object that the map is
on trigger a notification. The
change
parameter reports, in the form of keys within the map, which key-value pairs are added, removed, or modified during each write transaction. - MutableSet: Observing a property of a MutableSet's object triggers a notification for a change to that property, but does not trigger notifications for changes to its other properties. Insertions or deletions to the MutableSet or the object that the MutableSet is on trigger a notification.
- Results: Observing a property of the Result triggers a notification for a change to that property, but does not trigger notifications for changes to its other properties. Insertions or deletions to the Result trigger a notification.
Write Silently
You can write to a realm without sending a notification to a specific observer by passing the observer's notification token in an array to realm.write(withoutNotifying:_:):
Stop Watching for Changes
Observation stops when the token returned by an observe
call becomes
invalid. You can explicitly invalidate a token by calling its
invalidate()
method.
Notifications stop if the token is in a local variable that goes out of scope.
Key-value Observation
Key-value Observation Compliance
Realm Database objects are key-value observing (KVO) compliant for most properties:
- Almost all managed (non-ignored) properties on
Object
subclasses - The
invalidated
property onObject
andList
You cannot observe LinkingObjects
properties via Key-value observation.
You cannot add an object to a realm (with realm.add(obj)
or similar
methods) while it has any registered observers.
Managed vs. Unmanaged KVO Considerations
Observing the properties of unmanaged instances of Object
subclasses
works like any other dynamic property.
Observing the properties of managed objects works differently. With realm-managed objects, the value of a property may change when:
- You assign to it
- The realm is refreshed, either manually with
realm.refresh()
or automatically on a runloop thread - You begin a write transaction after changes on another thread
Realm applies changes made in the write transaction(s) on other threads at once. Observers see Key-value observation notifications at once. Intermediate steps do not trigger KVO notifications.
Say your app performs a write transaction that increments a property from 1 to 10. On the main thread, you get a single notification of a change directly from 1 to 10. You won't get notifications for every incremental change between 1 and 10.
Avoid modifying managed Realm objects from within
observeValueForKeyPath(_:ofObject:change:context:)
. Property values
can change when not in a write transaction, or as part of beginning a
write transaction.
Observing Realm Lists
Observing changes made to Realm List
properties is simpler than
NSMutableArray
properties:
- You don't have to mark
List
properties as dynamic to observe them. - You can call modification methods on
List
directly. Anyone observing the property that stores it gets a notification.
You don't need to use mutableArrayValueForKey(_:)
, although realm
does support this for code compatibility.
Examples of using Realm with ReactiveCocoa from Objective‑C , and ReactKit from Swift.