当我的红色、绿色或蓝色变量发生变化时,我尝试使用Combine来更新颜色。我看过的示例use 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沿着管道下降。现在,我们可以通过使用colorpub
订阅它来接收来自sink
的通知,并根据我们的喜好处置结果。让我们将一些接口对象的颜色设置为该颜色:let sink = colorpub.sink { self.view.backgroundColor = $0 }
或者,我可以使用
assign
编写它,这可能更干净,尽管backgroundColor
是可选的,因此我必须插入一个map
运算符,因为keypaths不是协变的:let assign = colorpub.map{Optional($0)}
.assign(to: \.backgroundColor, on: self.view)
现在,每当
colorObject
的r
、g
或b
更改时,视图的颜色都会相应更改。这并不是实现这一目标的唯一途径——离它很远!但这是一个用Combine完成工作的简单例子。一个可能有用的变体是将
colorpub
publisher向上移动到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)