UIView作为@EnvironmentObject的订阅者

时间:2020-06-25 23:48:10

标签: ios swift swiftui publish-subscribe combine

我有一个@EnvironmentObject,它在工作线程中进行了更新,并且几个SwiftUI视图订阅了对已发布值的更改。

这一切都很好。

但是我正在努力让UIView订阅@EnvironmentObject中的更改。

给予

@EnvironmentObject var settings: Settings 

where Settings is:

final class Settings {
    @Published var bar: Int = 0
    @Published var beat: Int = 1
    etc.
}

SwiftUI视图可以很好地根据发布的值更改进行更新。

但是现在,我想声明一个接收器,该接收器在符合UIViewRepresentable的UIView中接收发布的值。

我一直在研究“合并”书,并认为我可以使用以下内容声明一个.sink闭包:

   func subscribeToBeatChanges() {
        settings.$bar
            .sink(receiveValue: {
                bar in
                self.bar = bar
                print("Bar = \(bar)")
            } )
        settings.$beat
            .sink(receiveValue: {
                beat in
                self.beat = beat
                print("Beat = \(beat)")
                self.setNeedsDisplay()
            } )
    }
 

不幸的是,当调用subscribeToBeatChanges()时,闭包仅被调用一次。我想要的是每次@EnvironmentObject值中的@Published属性更改时都调用闭包。

我也尝试在UIViewRepresentable包装器中进行预订,并在makeUIView方法中进行了某些操作,但未成功。

我显然在做一些相当简单而根本的错误,并且肯定会朝正确的方向前进,因为我会cross目结舌地试图解决这个问题!

谢谢!

1 个答案:

答案 0 :(得分:0)

您必须存储对从AnyCancellable返回的.sink的引用:

private var cancellables = Set<AnyCancellable>()

func subscribeToBeatChanges() {
    settings.$bar
        .sink(receiveValue: {
            bar in
            self.bar = bar
            print("Bar = \(bar)")
        } )
        .store(in: &cancellables) // <-- store the instance
    settings.$beat
        .sink(receiveValue: {
            beat in
            self.beat = beat
            print("Beat = \(beat)")
            self.setNeedsDisplay()
        } )
        .store(in: &cancellables) // <-- store the instance
}

如果您不存储它,则AnyCancellable实例将自动取消对deinit的订阅。