如何使用Combine在两个类之间绑定属性



如何在引用ObservableObject类中的Published,但在两个类之间的视图中创建类似于绑定的机制?也就是说,从类A调用类B构造函数,传递来自类A的prop1。在类B中存在prop2,这些prop1和prop2应该相互镜像。

附言:附加的代码不起作用,只是直观地显示我想要什么。。。

PPS:类A中的prop1和类B中的prop2,必须按条件发布。它自己的观点也被订阅了

PPPS:重要的是在ClassB中有任何绑定逻辑,以便于重用。

class ClassA: ObservableObject {
@Published var prop1: Bool = false //When prop1 changed, it must be reflected in prop2
let classB: ClassB
init() {
classB = .init(prop2: _prop1) //Should stay that simple, no setup here, passing only property, ClassB doesn't know about ClassA.
}
}
class ClassB: ObservableObject {
@Published var prop2: Bool //When prop2 changed, it must be reflected in prop1
init(prop2: Published<Bool>) {
_prop2 = prop2
}
}

一个简单但通用的解决方案可能如下所示。

添加以下扩展:

extension Published.Publisher where Value: Equatable {
mutating func link(with other: inout Self) {
removeDuplicates().assign(to: &other)
other.removeDuplicates().assign(to: &self)
}
}

这只适用于符合Equatable的值,因为否则您可能会陷入无休止的循环。

然后调用ClassA:初始化器中的扩展

classB.$prop2.link(with: &$prop1)

原始答案

一个简单的解决方案是将以下代码放入ClassAinit中:

$prop1
.removeDuplicates()
.assign(to: &classB.$prop2) // mirror changes of prop1 into classB.prop2
classB.$prop2
.removeDuplicates()
.assign(to: &$prop1) // mirror changes of classB.prop2 into prop1

但是,我建议从ClassA中删除prop1,并分别通过classB.prop2classB.$prop2访问此值。这使得依赖关系更加清晰,并且不需要在两个位置存储和更新值。


注释中关于将逻辑放入ClassB的问题的答案

为此,您可以在ClassB中添加一个执行链接的函数:

fileprivate func linkProps(to classA: ClassA) {
$prop2
.removeDuplicates()
.assign(to: &classA.$prop1) // mirror changes of prop2 into classA.prop1
classA.$prop1
.removeDuplicates()
.assign(to: &$prop2) // mirror changes of classA.prop1 into prop2
}

然后在ClassAinit中调用此函数(以及其他需要调用的地方(:

init() {
classB = .init(prop2: _prop1)
classB.linkProps(to: self)
}

评论中关于阻止ClassB了解ClassA的问题的答案

这可以通过只将属性包装器的投影值传递到ClassB:上的函数中来实现

fileprivate func linkProp2(to prop1: inout Published<Bool>.Publisher) {
$prop2
.removeDuplicates()
.assign(to: &prop1) // mirror changes of prop2 into prop1
prop1
.removeDuplicates()
.assign(to: &$prop2) // mirror changes of prop1 into prop2
}

ClassA初始值设定项中的调用将如下所示:

classB.linkProp2(to: &$prop1)

最新更新