Migrating a SwiftUI iOS App from Core Data to Realm
Rate this tutorial
Porting an app that's using Core Data to Realm is very simple. If you have an app that already uses Core Data, and have been considering the move to Realm, this step-by-step guide is for you! The way that your code interacts with Core Data and Realm is very different depending on whether your app is based on SwiftUI or UIKit—this guide assumes SwiftUI (a UIKit version will come soon.)
You're far from the first developer to port your app from Core Data to Realm, and we've been told many times that it can be done in a matter of hours. Both databases handle your data as objects, so migration is usually very straightforward: Simply take your existing Core Data code and refactor it to use the .
This article was updated in July 2021 to replace
@Persistedannotation that was introduced in Realm-Cocoa 10.10.0.
This guide assumes that your app is written in Swift and built on SwiftUI rather than UIKit.
You can keep the default options and then select both the "Realm" and "RealmSwift" packages.
First things first. If your app is currently using Core Data, you'll need to work out which parts of your codebase include Core Data code. These will need to be refactored. Fortunately, there's a handy way to do this. While you could manually perform searches on the codebase looking for the relevant code, a much easier solution is to simply delete the Core Data import statements at the top of your source files:
Once this is done, every line of code implementing Core Data will throw a compiler error, and then it's simply a matter of addressing each compiler error, one at a time.
Not everyone (including me) likes the idea of not being able to build a project until every part of the port has been completed. If that's you, I'd suggest this approach:
- Leave the old code there for now.
- Add a new model, adding
Realmto the end of each class.
- Work through your views to move them over to your new model.
- Check and fix build breaks.
- Remove the
Realmfrom your model names using the Xcode refactoring feature.
- Check and fix build breaks.
- Find any files that still
import CoreDataand either remove that line or the entire file if it's now obsolete.
- Check and fix build breaks.
- Migrate existing user data from Core Data to Realm if needed.
- Remove the original model code.
In Core Data, changes to model objects are made against a managed object context object. Managed object context objects are created against a persistent store coordinator object, which themselves are created against a managed object model object.
Suffice to say, before you can even begin to think about writing or reading data with Core Data, you usually need to have code somewhere in your app to set up these dependency objects and to expose Core Data's functionality to your app's own logic. There will be a sizable chunk of "setup" Core Data code lurking somewhere.
When you're switching to Realm, all of that code can go.
In Realm, all of the setting up is done on your behalf when you access a Realm object for the first time, and while there are options to configure it—such as where to place your Realm data file on disk—it's all completely optional.
Your Realm schema will be defined in code by defining your Realm Object classes. There is no need for
.xcdatamodelfiles when working with Realm and so you can remove those Core Data files from your project.
In Core Data, the bread-and-butter class that causes subclassed model objects to be persisted is
NSManagedObject. The classes for these kinds of objects are pretty much standard:
Converting these managed object subclasses to Realm is really simple:
Note that top-level objects inherit from
Object, but objects that only exist within higher-level objects inherit from
Creating a new object in Core Data and then later modifying it is relatively trivial, only taking a few lines of code.
Adding an object to Core Data must be done using a
NSManagedObjectContext. This context is available inside a SwiftUI view through the environment:
That context can then be used to save the object to Core Data:
Realm requires that writes are made within a transaction, but the Realm Swift SDK hides most of that complexity when you develop with SwiftUI. The current Realm is made available through the SwiftUI environment and the view can access objects in it using the
A new object can then be stored in the Realm:
The Realm Swift SDK also hides the transactional complexity behind making updates to objects already stored in Realm. The
@ObservedRealmObjectproperty wrapper is used in the same way as
@ObservedObject—but for Realm managed objects:
To benefit from the transparent transaction functionality, make sure that you use the
@ObservedRealmObjectproperty wrapper as you pass Realm objects down the view hierarchy.
If you find that you need to directly update an attribute within a Realm object within a view, then you can use this syntax to avoid having to explicitly work with Realm transactions (where
In its most basic implementation, Core Data uses the concept of fetch requests in order to retrieve data from disk. A fetch can filter and sort the objects:
The equivalent code for such a query using Realm is very similar, but it uses the
@ObservedResultsproperty wrapper rather than
Once all of your code has been migrated to Realm, there's one more outstanding issue: How do you migrate any production data that users may already have on their devices out of Core Data and into Realm?
This can be a very complex issue. Depending on your app's functionality, as well as your users' circumstances, how you go about handling this can end up being very different each time.
We've seen two major approaches:
- Once you've migrated your code to Realm, you can re-link the Core Data framework back into your app, use raw NSManagedObject objects to fetch your users' data from Core Data, and then manually pass it over to Realm. You can leave this migration code in your app permanently, or simply remove it after a sufficient period of time has passed.
- If the user's data is replaceable—for example, if it is simply cached information that could be regenerated by other user data on disk—then it may be easier to simply blow all of the Core Data save files away, and start from scratch when the user next opens the app. This needs to be done with very careful consideration, or else it could end up being a bad user experience for a lot of people.
As with Core Data, your SwiftUI previews can add some data to Realm so that it's rendered in the preview. However, with Realm it's a lot easier as you don't need to mess with contexts and view contexts:
Thanks to their similarities in exposing data through model objects, converting an app from using Core Data to Realm is very quick and simple.
In this guide, we've focussed on the code that needs to be changed to work with Realm, but you'll be pleasantly surprised at just how much Core Data boilerplate code you're able to simply delete!
If you've been having trouble getting Core Data working in your app, or you're looking for a way to sync data between platforms, we strongly recommend giving Realm a try, to see if it works for you. And if it does, please be sure to let us know!