使用 Combine 和 SwiftUI 在 Realm 中观察收集结果
Posted
技术标签:
【中文标题】使用 Combine 和 SwiftUI 在 Realm 中观察收集结果【英文标题】:Observe Collection Results in Realm with Combine and SwiftUI 【发布时间】:2021-02-05 00:37:21 【问题描述】:我正在尝试this quick start for SwiftUI and 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
的集合上设置一个通知监听器一样?
【问题讨论】:
【参考方案1】:从技术上讲,您可以将 sink
连接到 state.workspaces
(state.$workspaces.sink()
),但在这种情况下,我认为您将问题复杂化了。
您的ContentView
(AppState
) 中已经有一个@ObservableObject,它正在为您管理结果。因此,将ItemsView
更改为仅将其作为参数:
var workspaces: Results<Workspace>?
它不需要是@ObservedObject
——无论是在那个视图中还是在它的父视图中,它都会被重新渲染。它在这里必须是可选的,因为它是 AppState
上的可选值,除非你想通过强制展开 (!
) 继续传递它,但这通常是个坏主意,因为如果它会崩溃曾经是事实上nil
。
此外,在您的Realm
代码中,请确保它与您所遵循的教程相匹配。例如,您有Publisher.sink
,实际上应该是realmPublisher.sink
【讨论】:
非常感谢您的帮助。我是Combine的新手,所以我的理解非常有限。我会试试你的建议。我的代码中确实有realmPublisher
,只是在我的问题中打错了字。我会解决的。再次感谢。
我尝试了你的建议。我在应用加载时获得初始数据,但没有收到更改通知。 AppState()
对象似乎没有传播其更改。据我了解,我需要将workspaces
设为@StateObject
才能将自己绑定到父@ObservedObject
,但由于workspaces
不是对象,所以我不能。
它不是必须是 @StateObject —— 必须有其他事情发生。当您在接收器内打印工作区的内容时会发生什么?
看起来什么都没有发生。更新上没有打印任何内容(我直接在 Realm 数据库中进行更改以触发更改)。
嗯,这意味着不是组合部分不起作用——而是领域部分【参考方案2】:
你是对的,Results
是一个结构体,因此不能被@StateObject
或@ObservedObject
覆盖。您的解决方法现在适合。
https://github.com/realm/realm-cocoa/pull/7045 发布后,您将能够使用新的 Realm 属性包装器之一将您的 Results
直接嵌入到视图中。在此发布时,该名称将是 @FetchRealmResults
,但可能会发生变化。
【讨论】:
这听起来正是我想要的。所以你会抽象出 Publisher 的东西,让我专注于在需要它们的地方获取Results
。我认为这类似于Core Data 对Combine 所做的事情。让我知道我需要为谁购买披萨才能发布 PR。 ?以上是关于使用 Combine 和 SwiftUI 在 Realm 中观察收集结果的主要内容,如果未能解决你的问题,请参考以下文章
使用 Combine 和 SwiftUI 显示变化值的最简洁方式是啥?
使用 Combine 和 SwiftUI 在 Realm 中观察收集结果
如何使用 SwiftUI 和 Combine 检测 Datepicker 的值变化?