响应更改 - SwiftUI
观察对象
Swift SDK提供了 @ObservedRealmObject属性包装器,该包装器可在观察到的对象发生更改时使视图失效。 您可以使用此属性包装器创建一个视图,该视图在观察到的对象发生更改时自动更新。
struct DogDetailView: View { var dog: Dog var body: some View { VStack { Text(dog.name) .font(.title2) Text("\(dog.name) is a \(dog.breed)") AsyncImage(url: dog.profileImageUrl) { image in image.resizable() } placeholder: { ProgressView() } .aspectRatio(contentMode: .fit) .frame(width: 150, height: 150) Text("Favorite toy: \(dog.favoriteToy)") } } }
观察查询结果
Swift SDK 提供了@ObservedResults属性包装器,可让您观察查询结果的集合。 您可以对 ObservedResults 集合执行快速写入,并且当观察到的查询发生更改时,视图会自动更新。 例如,您可以使用 onDelete
从观察到的狗列表中删除一条狗。
注意
@ObservedResults
属性包装器用于“SwiftUI 视图”。如果您想观察视图模型中的结果,请注册更改监听器。
struct DogsView: View { Dog.self) var dogs ( /// The button to be displayed on the top left. var leadingBarButton: AnyView? var body: some View { NavigationView { VStack { // The list shows the dogs in the realm. // The ``@ObservedResults`` above implicitly opens a realm and retrieves // all the Dog objects. We can then pass those objects to views further down the // hierarchy. List { ForEach(dogs) { dog in DogRow(dog: dog) }.onDelete(perform: $dogs.remove) }.listStyle(GroupedListStyle()) .navigationBarTitle("Dogs", displayMode: .large) .navigationBarBackButtonHidden(true) .navigationBarItems( leading: self.leadingBarButton, // Edit button on the right to enable rearranging items trailing: EditButton()) }.padding() } } }
对观察结果排序
@ObservedResults属性包装器可以采用SortDescriptor参数对查询结果进行排序。
struct SortedDogsView: View { Dog.self, ( sortDescriptor: SortDescriptor(keyPath: "name", ascending: true)) var dogs var body: some View { NavigationView { // The list shows the dogs in the realm, sorted by name List(dogs) { dog in DogRow(dog: dog) } } } }
提示
您不能将计算属性用作 @ObservedResults
的 SortDescriptor
。
观察分节结果
10.29.0 版中的新增功能。
您可以观察结果集,该结果集通过从对象属性生成的键划分为多个部分。我们在模型中添加了一个计算变量,但这个变量并不持久存在;我们只是用它来对结果集进行分区。
var firstLetter: String { guard let char = name.first else { return "" } return String(char) }
然后我们可以使用 @ObservedSectionedResults 属性包装器来观察根据计算变量键划分的结果集。
Dog.self, ( sectionKeyPath: \.firstLetter) var dogs
您可以使用这些观察到的分节结果来填充按节划分的“列表”视图:
struct SectionedDogsView: View { Dog.self, ( sectionKeyPath: \.firstLetter) var dogs /// The button to be displayed on the top left. var leadingBarButton: AnyView? var body: some View { NavigationView { VStack { // The list shows the dogs in the realm, split into sections according to the keypath. List { ForEach(dogs) { section in Section(header: Text(section.key)) { ForEach(section) { dog in DogRow(dog: dog) } } } } .listStyle(GroupedListStyle()) .navigationBarTitle("Dogs", displayMode: .large) .navigationBarBackButtonHidden(true) .navigationBarItems( leading: self.leadingBarButton, // Edit button on the right to enable rearranging items trailing: EditButton()) }.padding() } } }
观察应用程序状态
如果您的应用使用Atlas Device Sync ,您可以观察应用程序对象对登录状态更改的React 。 这样,您的应用就能在有app.currentUser
的情况下执行操作,或者在没有app.currentUser
的情况下引导用户登录。
由于 Realm 会在设备上缓存用户凭据,因此应用可以在具有 app.currentUser
的情况下离线运行。
/// This view observes the Realm app object. /// Either direct the user to login, or open a realm /// with a logged-in user. struct FlexibleSyncContentView: View { // Observe the Realm app object in order to react to login state changes. var app: RealmSwift.App var body: some View { if let user = app.currentUser { // 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) } else { // If there is no user logged in, show the login view. LoginView() } } }