我正在尝试使用组合来更新颜色,当我的红色、绿色或蓝色变量发生变化时。我看过的例子使用 sink(),这对我来说似乎很合适,但 eraseToAnySubscriber 是 MIA,我找不到替代品。
似乎有效的方法是对计算变量使用 assign(),但这似乎有点黑客。
init() {
redCancellable = red.hasChanged.receive(on: RunLoop.main).assign(to: .rgbUpdated, on: self)
}
有没有办法保存 sink() 返回的值?
这听起来像是CombineLatest的工作。是的,sink
是以您喜欢的任何方式处理管道末端的完美方法。
下面是一个简单的示例。我将从一个具有r
、g
和b
变量的对象开始:
class ColorObject {
@Published var r : CGFloat = 1
@Published var g : CGFloat = 1
@Published var b : CGFloat = 1
}
现在想象一下,我们在某个地方有一个该对象的实例;称之为colorObject
。然后我们可以配置一个发布者:
let rpub = colorObject.$r
let gpub = colorObject.$g
let bpub = colorObject.$b
let colorpub = Publishers.CombineLatest3(rpub,gpub,bpub)
.map { UIColor(red: $0.0, green: $0.1, blue: $0.2, alpha: 1) }
结果是,每当colorObject
的r
或g
或b
更改时,UIColor 就会沿着管道向下移动。现在,我们可以通过sink
订阅colorpub
来接收来自的通知,并按照我们喜欢的方式处理结果。让我们将某个界面对象的颜色设置为该颜色:
let sink = colorpub.sink { self.view.backgroundColor = $0 }
或者,我可以使用assign
编写它,这可能更干净,尽管backgroundColor
是可选的,所以我必须插入一个map
运算符,因为 keyPath 不是协变的:
let assign = colorpub.map{Optional($0)}
.assign(to: .backgroundColor, on: self.view)
现在,每当colorObject
的r
、g
或b
发生变化时,我们视图的颜色也会随之改变。
这不是实现这一目标的唯一途径——远非如此!但这是使用 Combine 完成工作的简单示例。一个可能有用的变体是将colorpub
发布者向上移动到 ColorObject 中;这样,ColorObject 直接发送颜色本身:
class ColorObject {
@Published var r : CGFloat = 1
@Published var g : CGFloat = 1
@Published var b : CGFloat = 1
lazy var colorpub = Publishers.CombineLatest3($r,$g,$b)
.map { UIColor(red: $0.0, green: $0.1, blue: $0.2, alpha: 1) }
}
这不会改变sink
或assign
:
let sink = colorObject.colorpub.sink { // ... whatever
// or
let assign = colorObject.colorpub.map{Optional($0)}
.assign(to: .backgroundColor, on: self.view)