配置并打开 Realm - SwiftUI
Swift SDK提供属性包装器,以便以SwiftUI友好的方式打开域 。
您可以:
使用
defaultConfiguration
隐式打开域或指定其他配置。 这适用于非同步和同步 Realm。始终在打开 同步 Realm 之前下载更改,这会在用户离线时超时。
即使用户离线,也可打开同步 Realm 。 该 Realm 可能缺少最新数据。
使用配置打开Realm
当您使用@ObservedRealmObject或@ObservedResults时,这些属性包装器会隐式打开一个域并检索指定的对象或结果。
// Implicitly use the default realm's objects(Dog.self) Dog.self) var dogs (
注意
@ObservedResults
属性包装器用于“SwiftUI 视图”。如果您想观察视图模型中的结果,请注册更改监听器。
如果您未指定配置,这些属性包装器将使用defaultConfiguration 。 您可以全局设立defaultConfiguration ,应用中的属性包装器在隐式打开域时可以使用该配置。
您可以提供属性包装器用于隐式打开域的替代配置。 在应用中使用多个配置时,您可能需要执行此操作,例如同时具有SyncConfiguration和本地配置的情况。 为此,请创建显式配置。 然后,使用环境注入将相应配置传递给需要它们的视图。 将配置传递给属性包装器打开域的视图时,会使用传递的配置而不是defaultConfiguration
。
打开同步 Realm
版本 10.12.0 新增。
这些 SwiftUI 属性包装器打开同步 Realm 并填充视图。 这些属性包装器之间的主要区别在于用户是否必须在线:
要在打开域之前从Atlas App Services应用下载更新,请使用@AsyncOpen属性包装器。 这要求用户具有网络连接。
要在无论用户是否有网络连接的情况下都打开同步 Realm,请使用@AutoOpen属性包装器。 此属性包装器使开发者能够在其应用程序中设计离线优先功能。
提示
迁移到 Flexible Sync
您可以自动将Atlas App Services Device Sync模式从基于分区的同步迁移到Flexible Sync 。 这样,您就可以利用更具表现力和更精细的 Flexible Sync 订阅和权限来管理用户可以读取和写入的同步数据。 有关更多信息,请参阅从基于分区的同步迁移到 Flexible Sync。
在打开同步Realm之前下载更改
对于需要从服务器获取最新信息的应用,请使用@AsyncOpen属性包装器,例如用户可以在多个设备上玩的带有实时排行榜的游戏应用。 这可确保用户永远不会使用包含过时数据的应用程序。
10.27.0版本新增。
Realm Swift SDK版本10.27.0 添加了属性包装器的Flexible Sync版本,以使用SwiftUI打开Realm 。 您可以在打开域后在.onAppear
中添加订阅查询。
4000) var asyncOpen (appId: flexibleSyncAppId, timeout:
版本 10.28.0 新增内容。
您可以使用initialSubscriptions
参数创建FlexibleSyncConfiguration() 。 您可以使用此参数订阅配置中的 Flexible Sync 查询。 如果运行多次(示例,如果在定期重新加载的视图中),请在添加订阅之前检查订阅是否已存在。 再次添加相同的订阅会引发错误。
// Create a `flexibleSyncConfiguration` with `initialSubscriptions`. // We'll inject this configuration as an environment value to use when opening the realm // in the next view, and the realm will open with these initial subscriptions. let config = user.flexibleSyncConfiguration(initialSubscriptions: { subs in let peopleSubscriptionExists = subs.first(named: "people") let dogSubscriptionExists = subs.first(named: "dogs") // Check whether the subscription already exists. Adding it more // than once causes an error. if (peopleSubscriptionExists != nil) && (dogSubscriptionExists != nil) { // Existing subscriptions found - do nothing return } else { // Add queries for any objects you want to use in the app // Linked objects do not automatically get queried, so you // must explicitly query for all linked objects you want to include. subs.append(QuerySubscription<Person>(name: "people")) subs.append(QuerySubscription<Dog>(name: "dogs")) } })
然后,将配置作为 环境对象传递给包含属性包装器的视图。
OpenFlexibleSyncRealmView() .environment(\.realmConfiguration, config)
有关完整示例,请参阅SwiftUI快速入门。
要使用基于分区的同步打开域 ,请将partitionValue
添加到属性包装器:
YOUR_APP_SERVICES_APP_ID_HERE, partitionValue: "", timeout: 4000) var asyncOpen (appId:
此 SwiftUI 属性包装器为当前用户启动Realm.asyncOpen()
。 属性包装器发布由AsyncOpenState 枚举表示的状态,您可以使用该状态来更新视图。
例子
此示例说明了使用@AsyncOpen
在视图中打开域的一种方法。 首先,检查是否有用户或日志。 然后,尝试打开域,打开AsyncOpenState
以显示适当的视图。 当域成功打开后,将其作为环境值注入以填充视图。
/// 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) } } }
/// This view opens a synced realm. struct OpenPartitionBasedSyncRealm: View { // @AsyncOpen attempts to connect to the server and download remote changes // before the realm opens. If there is no network connection, // AsyncOpen cannot load changes and the realm does not open. // We can use an empty string as the partitionValue here because we're // injecting the user.id as an environment value from the LoginView. YOUR_APP_SERVICES_APP_ID_HERE, partitionValue: "", timeout: 4000) var asyncOpen (appId: 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) } } }
离线打开同步 Realm
与@AsyncOpen
一样, @AutoOpen 会尝试在打开域之前下载更新。 但是,如果网络连接不可用,此方法则会打开一个包含设备上数据的域 。
对于用户处理可能过时的数据没有问题的应用程序,请使用此属性包装器,例如用户应该能够在设备上处理数据的笔记应用程序
"app_id") var autoOpen (appId:
"app_id", partitionValue: <partition_value>) var autoOpen (appId:
此 SwiftUI 属性包装器会在为当前用户打开 Realm 之前尝试下载更新。 如果没有互联网连接,此属性包装器则会返回给定appId
和 Flexible Sync 或基于分区的同步配置的最新版本的本地 Realm 文件。
属性包装器发布由AsyncOpenState枚举表示的状态,您可以使用该状态来更新视图。 有关完整示例,请参阅上面的@AsyncOpen
代码示例。