Docs Menu
Docs Home
/ /
Atlas Device SDKs
/ / /

Change an Object Model - SwiftUI

On this page

  • Overview
  • Use Migrated Data with SwiftUI
  • Set a Default Configuration
  • Pass the Configuration Object as an Environment Object
  • Explicitly Pass the Updated Configuration to a Realm SwiftUI Property Wrapper

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.

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.

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:

@Persisted 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.

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)

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)
@ObservedResults(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.
@AsyncOpen(appId: flexibleSyncAppId, timeout: 4000) var asyncOpen
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.

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.
@ObservedResults(Dog.self, configuration: config) var dogs

Back

Realm Object Models