我正在尝试快速启动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
,但这可能会发生变化。