使用Combine和SwiftUI观察Realm的收集结果



我正在尝试快速启动SwiftUI和Combine,以尝试和理解如何连接我的Realm数据库到Combine。

这个例子观察一个RealmSwift.List,并用它的数据填充一个表。这是一个指向子类的链表。我想知道如何观察Results集合,以便我可以跟踪整个Realm类的任何更改。

例如,假设我有一个Workspace类:

class Workspace: Object, ObjectKeyIdentifiable{
@objc dynamic var id = UUID().uuidString
@objc dynamic var name = ""
@objc dynamic var archived = false
}

在状态对象中,我可以像这样设置Results<Workspace>变量:

class AppState: ObservableObject {
@Published var workspaces: Results<Workspace>?
var cancellables = Set<AnyCancellable>()

init(){
let realmPublisher = PassthroughSubject<Realm, Error>()
realmPublisher
.sink(receiveCompletion: { _ in }, receiveValue: { realm in
//Get the Results
self.workspaces = realm.objects(Workspace.self)
})
.store(in: &cancellables)
realmPublisher.send(try! Realm())
return
}
}

但是当要观察对象的时候,我不能,因为Results不是一个对象(我假设)。

struct ContentView: App {
@ObservedObject var state = AppState()
var view: some View {
ItemsView(workspaces: state.workspaces!)  
}
var body: some Scene {
WindowGroup {
view.environmentObject(state)
}
}
}
struct ItemsView: View {
@ObservedObject var workspaces: Results<Workspace> //<!-- Error
var body: some View {
//...
}
}
Xcode给出了workspaces属性的语法错误:

属性类型'Results'不匹配其包装类型'ObservedObject'的'wrappedValue'属性

是否有可能观察一组Results,就像我们可以在Results集合上有一个通知侦听器一样?

从技术上讲,您可以将sink连接到state.workspaces(state.$workspaces.sink()),但在这种情况下,我认为您将问题复杂化了。

你已经有一个@ObservableObject在你的ContentView(AppState)是为你管理的结果。因此,将ItemsView作为一个参数:

var workspaces: Results<Workspace>?

它不需要是@ObservedObject——不管怎样,不管它是在那个视图还是它的父视图中被观察到,它都会被重新渲染。它在这里必须是可选的,因为它在AppState上是一个可选的值,除非你想继续传递它与强制展开(!),但这通常是一个坏主意,因为如果实际上是nil,它会崩溃。

同样,在上面的Realm代码中,确保它与您所遵循的教程匹配。例如,Publisher.sink实际上应该是realmPublisher.sink

你是正确的,Results是一个结构体,因此不能被@StateObject@ObservedObject覆盖。你的解决方法现在是合适的。

一旦https://github.com/realm/realm-cocoa/pull/7045发布,您将能够使用一个新的Realm属性包装器将您的Results直接嵌入到视图中。在发布这篇文章时,这将是@FetchRealmResults,但这可能会发生变化。

相关内容

  • 没有找到相关文章

最新更新