On this page
Swift's concurrency system provides built-in support for writing asynchronous and parallel code in a structured way. For a detailed overview of the Swift concurrency system, refer to the Swift Programming Language Concurrency topic.
As you implement concurrency features in your app, consider this caveat about Realm's threading model and Swift concurrency threading behaviors.
Anywhere you use the Swift keyword
await marks a possible suspension
point in the execution of your code. With Swift 5.7, once your code suspends,
subsequent code might not execute on the same thread. This means that
anywhere you use
await in your code, the subsequent code could be
executed on a different thread than the code that precedes or follows it.
This is inherently incompatible with Realm's live object paradigm. Live objects, collections, and realm instances are thread-confined: that is, they are only valid on the thread on which they were created. Practically speaking, this means you cannot pass live instances to other threads. However, Realm Database offers several mechanisms for sharing objects across threads. These mechanisms typically require your code to do some explicit handling to safely pass data across threads.
You can use some of these mechanisms, such as frozen objects or the @ThreadSafe property wrapper, to safely use Realm objects and instances
across threads with the
await keyword. You can also avoid
threading-related issues by marking any asynchronous Realm code with
@MainActor to ensure your apps always execute this code on the main
As a general rule, keep in mind that using Realm in an
without incorporating threading protection may yield inconsistent behavior.
Sometimes, the code may succeed. In other cases, it may throw an error
related to writing on an incorrect thread.
Realm does not provide Swift async/await support for reading or writing objects. However, the Realm Swift SDK does provide an API to safely perform background writes without requiring you to use threading protection. For more information, refer to Perform Background Writes below.
If you have specific feature requests related to Swift async/await APIs, check out the MongoDB Feedback Engine for Realm. The Realm Swift SDK team plans to continue to develop concurrency-related features based on community feedback and Swift concurrency evolution.
A commonly-requested use case for asynchronous code is to perform write
operations in the background without blocking the main thread. While the
Realm Swift SDK does not currently support an async/await API for this, it
does have an API specifically for performing background writes:
This API allows you to add, update, or delete objects in the background without using frozen objects or passing a thread-safe reference. With this API, waiting to obtain the write lock and committing a transaction occur in the background. The write block itself runs on the calling thread. This provides thread-safety without requiring you to manually handle frozen objects or passing references across threads.
However, while the write block itself is executed, this does block new
transactions on the calling thread. This means that a large write using
writeAsync API could block small, quick writes while it executes.
For more information, including a code example, refer to: Perform a Background Write.
Swift concurrency provides APIs to manage Tasks and TaskGroups. The Swift concurrency documentation defines a task as a unit of work that can be run asynchronously as part of your program. Task allows you to specificially define a unit of asynchronous work. TaskGroup lets you define a collection of Tasks to execute as a unit under the parent TaskGroup.
Tasks and TaskGroups provide the ability to yield the thread to other important work or to cancel a long-running task that could be blocking other operations. To get these benefits, you might be tempted to use Tasks and TaskGroups to manage realm writes in the background.
However, the thread-confined constraints described in Suspending
Execution with Await above apply in
the Task context. If your Task contains
await points, subsequent code
might run or resume on a different thread and violate Realm's thread confinement.
You must annotate functions that you run in a Task context with
to ensure code that accesses Realm only runs on the main thread. This negates
some of the benefits of using Tasks, and may mean this is not a good design
choice for apps that use Realm unless you are using Tasks solely for
networking activities like managing users.
Actor isolation provides the perception of confining Realm access to a dedicated actor, and therefore seems like a safe way to manage Realm access in an asynchronous context.
However, using Realm in a non-
@MainActor async function is currently
In Swift 5.6, this would often work by coincidence. Execution after an
await would continue on whatever thread the awaited thing ran on.
await Realm() in an async function would result in the code
following that running on the main thread until your next call to an
Swift 5.7 instead hops threads whenever changing actor isolation contexts. An unisolated async function always runs on a background thread instead.
If you have code which uses
await Realm() and works in 5.6, marking
the function as
@MainActor will make it work with Swift 5.7. It will
function how it did - unintentionally - in 5.6.
The Swift SDK team is working on improving support for actor isolation. If you have specific feature requests related to actor isolation, check the status of similar feature requests or leave feedback through the MongoDB Feedback Engine for Realm.
Most often, the error you see related to accessing Realm through concurrency
Realm accessed from incorrect thread. This is due to the
thread-isolation issues described on this page.
To avoid threading-related issues in code that uses Swift concurrency features:
Do not change execution contexts when accessing a realm. If you open a realm on the main thread to provide data for your UI, annotate subsequent functions where you access the realm asynchronously with
@MainActorto ensure it always runs on the main thread. Remember that
awaitmarks a suspension point that could change to a different thread.
writeAsyncAPI to perform a background write. This manages realm access in a thread-safe way without requiring you to write specialized code to do it yourself. This is a special API that outsources aspects of the write process - where it is safe to do so - to run in an async context. You do not use this method with Swift's
async/awaitsyntax - use this method synchronously in your code.
If you want to explicitly write concurrency code where accessing a realm is done in a thread-safe way, you can explicitly pass instances across threads or use frozen objects where applicable to avoid threading-related crashes. This does require a good understanding of Realm's threading model, as well as being mindful of Swift concurrency threading behaviors.