如何使用 Combine 实现派生 属性?
How to implement derived property using Combine?
我有一个具有两个属性的可观察对象
class Demo: ObservableObject {
@Published var propertyA: Bool
@Published var propertyB: Bool
}
现在我想添加一个派生的 属性 "propertyC" 即 "true" 如果 属性A 和 属性B 都为真。
我发现了类似的问题,但答案并不令我满意。我正在寻找一种使用 Combine Framework 而不是 "didSet" 方法的解决方案,因为我的真实世界项目从两个以上的其他属性计算派生的 属性。
当我在 SwiftUI 视图中使用派生的 属性C 时,它应该在 属性A 或 属性B 发生变化时触发刷新,即使我不使用它们在视图中。
这是可能的方法(使用 Xcode 11.2 / iOS 13.2 测试)
class Demo: ObservableObject {
@Published var propertyA: Bool = false
@Published var propertyB: Bool = false
@Published var propertyC: Bool = false
private var subscribers = Set<AnyCancellable>()
init() {
Publishers.CombineLatest(_propertyA.projectedValue, _propertyB.projectedValue)
.receive(on: RunLoop.main)
.map { [=10=] && }
.assign(to: \.propertyC, on: self)
.store(in: &subscribers)
}
}
// view for testing, works in Preview as well
struct FastDemoTest: View {
@ObservedObject var demo = Demo()
var body: some View {
VStack {
Button("Toggle A") { self.demo.propertyA.toggle() }
Button("Toggle B") { self.demo.propertyB.toggle() }
Divider()
Text("Result of C: \( demo.propertyC ? "true" : "false" )")
}
}
}
所有学分都应该归 Rob(请参阅他对此问题的注释)
class Demo: ObservableObject {
@Published var propertyA: Bool = false
@Published var propertyB: Bool = false
var propertyC: Bool {
propertyA && propertyB
}
}
struct ContentView: View {
@ObservedObject var demo = Demo()
var body: some View {
VStack {
Button("Toggle A = \(demo.propertyA.description)") { self.demo.propertyA.toggle() }
Button("Toggle B = \(demo.propertyB.description)") { self.demo.propertyB.toggle() }
Divider()
Text("Result of C: \(demo.propertyC.description)")
}
}
}
我有一个具有两个属性的可观察对象
class Demo: ObservableObject {
@Published var propertyA: Bool
@Published var propertyB: Bool
}
现在我想添加一个派生的 属性 "propertyC" 即 "true" 如果 属性A 和 属性B 都为真。
我发现了类似的问题,但答案并不令我满意。我正在寻找一种使用 Combine Framework 而不是 "didSet" 方法的解决方案,因为我的真实世界项目从两个以上的其他属性计算派生的 属性。
当我在 SwiftUI 视图中使用派生的 属性C 时,它应该在 属性A 或 属性B 发生变化时触发刷新,即使我不使用它们在视图中。
这是可能的方法(使用 Xcode 11.2 / iOS 13.2 测试)
class Demo: ObservableObject {
@Published var propertyA: Bool = false
@Published var propertyB: Bool = false
@Published var propertyC: Bool = false
private var subscribers = Set<AnyCancellable>()
init() {
Publishers.CombineLatest(_propertyA.projectedValue, _propertyB.projectedValue)
.receive(on: RunLoop.main)
.map { [=10=] && }
.assign(to: \.propertyC, on: self)
.store(in: &subscribers)
}
}
// view for testing, works in Preview as well
struct FastDemoTest: View {
@ObservedObject var demo = Demo()
var body: some View {
VStack {
Button("Toggle A") { self.demo.propertyA.toggle() }
Button("Toggle B") { self.demo.propertyB.toggle() }
Divider()
Text("Result of C: \( demo.propertyC ? "true" : "false" )")
}
}
}
所有学分都应该归 Rob(请参阅他对此问题的注释)
class Demo: ObservableObject {
@Published var propertyA: Bool = false
@Published var propertyB: Bool = false
var propertyC: Bool {
propertyA && propertyB
}
}
struct ContentView: View {
@ObservedObject var demo = Demo()
var body: some View {
VStack {
Button("Toggle A = \(demo.propertyA.description)") { self.demo.propertyA.toggle() }
Button("Toggle B = \(demo.propertyB.description)") { self.demo.propertyB.toggle() }
Divider()
Text("Result of C: \(demo.propertyC.description)")
}
}
}