2

当我的红色、绿色或蓝色变量发生变化时,我正在尝试使用组合来更新颜色。我看过的示例使用 sink(),这对我来说似乎很合适,但 eraseToAnySubscriber 是 MIA,我找不到替代品。

似乎可行的是对计算变量使用 assign() ,但这似乎有点 hack。


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

有什么方法可以保存 sink() 返回的值吗?

4

1 回答 1

2

这听起来像是 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'rgb改变时,UIColor 都会从管道中下来。colorpub现在我们可以通过订阅它来接收通知,sink并按照我们喜欢的方式处理结果。让我们将一些界面对象的颜色设置为该颜色:

let sink = colorpub.sink { self.view.backgroundColor = $0 }

或者,我可以使用 来编写它assign,这可能更干净,但backgroundColor它是一个 Optional ,所以我必须插入一个map运算符,因为 keyPaths 不是协变的:

let assign = colorpub.map{Optional($0)}
    .assign(to: \.backgroundColor, on: self.view)

现在,每当colorObject' rgb变化时,我们视图的颜色都会相应变化。

这不是实现这一目标的唯一方法——远非如此!但这是使用 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) }
}

这不会改变sinkor assign

let sink = colorObject.colorpub.sink { // ... whatever
// or
let assign = colorObject.colorpub.map{Optional($0)}
    .assign(to: \.backgroundColor, on: self.view)
于 2019-07-26T18:44:57.413 回答