当我的红色、绿色或蓝色变量发生变化时,我尝试使用Combine来更新颜色。我看过的示例use sink()对我来说似乎是合适的,但是eraseToAnySubscriber是mia,我找不到替代者。
似乎有效的方法是对计算变量使用assign(),但这有点像黑客。


init() {
        redCancellable = red.hasChanged.receive(on: RunLoop.main).assign(to: \.rgbUpdated, on: self)
    }

有没有办法保存sink()返回的值?

最佳答案

这听起来像是combinelatest的工作。是的,sink是以您喜欢的任何方式处理管道末端的完美方法。
下面是一个简单的例子。我将从一个具有rgb变量的对象开始:

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) }

结果是,每次colorObjectrgb发生变化时,都会有一个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)

现在,每当colorObjectrgb更改时,视图的颜色都会相应更改。
这并不是实现这一目标的唯一途径——离它很远!但这是一个用Combine完成工作的简单例子。一个可能有用的变体是将colorpubpublisher向上移动到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) }
}

这对sinkassign没有任何影响:
let sink = colorObject.colorpub.sink { // ... whatever
// or
let assign = colorObject.colorpub.map{Optional($0)}
    .assign(to: \.backgroundColor, on: self.view)

09-03 23:49