Change an Object Model - SwiftUI
On this page
Note
Modify Schema Properties of a Synced Realm
The following page demonstrates how to modify schema properties of a local realm. Learn how to modify schema properties of a synced realm.
Overview
When you update your object schema, you must increment the schema version and perform a migration. You might update your object schema between major version releases of your app.
For information on how to actually perform the migration, see: Change an Object Model.
This page focuses on how to use migrated data in SwiftUI Views.
Use Migrated Data with SwiftUI
To perform a migration:
Update your schema and write a migration block, if required
Specify a Realm.Configuration that uses this migration logic and/or updated schema version when you initialize your realm.
From here, you have a few options to pass the configuration object. You can:
Set the configuration as the default configuration. If you do not explicitly pass the configuration via environment injection or as a parameter, property wrappers use the default configuration.
Use environment injection to provide this configuration to the first view in your hierarchy that uses Realm
Explicitly provide the configuration to a Realm property wrapper that takes a configuration object, such as
@ObservedResults
or@AsyncOpen
.
Example
For example, you might want to add a property to an existing object. We
could add a favoriteTreat
property to the Dog
object in DoggoDB:
var favoriteTreat = ""
After you add your new property to the schema, you must increment the
schema version. Your Realm.Configuration
might look like this:
let config = Realm.Configuration(schemaVersion: 2)
Declare this configuration somewhere that is accessible to the first view
in the hierarchy that needs it. Declaring this above your @main
app
entrypoint makes it available everywhere, but you could also put it in
the file where you first open a realm.
Set a Default Configuration
You can set a default configuration in a SwiftUI app the same as any other Realm Swift app. Set the default realm configuration by assigning a new Realm.Configuration instance to the Realm.Configuration.defaultConfiguration class property.
// Open the default realm let defaultRealm = try! Realm() // Open the realm with a specific file URL, for example a username let username = "GordonCole" var config = Realm.Configuration.defaultConfiguration config.fileURL!.deleteLastPathComponent() config.fileURL!.appendPathComponent(username) config.fileURL!.appendPathExtension("realm") let realm = try! Realm(configuration: config)
Pass the Configuration Object as an Environment Object
Once you have declared the configuration, you can inject it as an environment
object to the first view in your hierarchy that opens a realm. If you are
using the @ObservedResults
or @ObservedRealmObject
property wrappers,
these views implicitly open a realm, so they also need access to this
configuration.
.environment(\.realmConfiguration, config)
If your app uses either a local or a Synced realm, the first view in the hiearchy that opens a realm varies depending on whether you're using the app with or without Sync.
Without sync, you can pass the realm configuration environment object directly
to the LocalOnlyContentView
:
.environment(\.realmConfiguration, config)
Which opens a realm implicitly with:
struct LocalOnlyContentView: View { // Implicitly use the default realm's objects(Dog.self) Dog.self) var dogs ( var body: some View { if dogs.first != nil { // If dogs exist, go to the DogsView DogsView() } else { // If there is no Dog object, add one here. AddDogView() } } }
However, when your app uses Sync, you the Realm explicitly using the
@AsyncOpen
or @AutoOpen
property wrapper:
/// This view opens a synced realm. struct OpenFlexibleSyncRealmView: View { // We've injected a `flexibleSyncConfiguration` as an environment value, // so `@AsyncOpen` here opens a realm using that configuration. 4000) var asyncOpen (appId: flexibleSyncAppId, timeout: var body: some View { switch asyncOpen { // Starting the Realm.asyncOpen process. // Show a progress view. case .connecting: ProgressView() // Waiting for a user to be logged in before executing // Realm.asyncOpen. case .waitingForUser: ProgressView("Waiting for user to log in...") // The realm has been opened and is ready for use. // Show the content view. case .open(let realm): // Do something with the realm UseRealmView(realm: realm) // The realm is currently being downloaded from the server. // Show a progress view. case .progress(let progress): ProgressView(progress) // Opening the Realm failed. // Show an error view. case .error(let error): ErrorView(error: error) } } }
So you must pass the environment object to the view that explicitly
opens the realm. In this case, the OpenFlexibleSyncRealmView
.
The important thing to remember is to make sure to pass the
Realm.Configuration
that encompasses your migration logic to any view
hierarchy that implicitly or explicitly opens a realm.
Explicitly Pass the Updated Configuration to a Realm SwiftUI Property Wrapper
You can explicitly pass the configuration object to a Realm SwiftUI
property wrapper that takes a configuration object, such as @ObservedResults
or @AutoOpen
. In this case, you might pass it directly to @ObservedResults
in our DogsView
.
// Use a `config` that you've passed in from above. Dog.self, configuration: config) var dogs (