You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用@Observable宏时,如何从属性获取Publisher监听值变化?

使用@Observable宏监听属性变化的Combine方案

在Swift的新@Observable宏系统中,确实没有像@Published那样自动生成带$前缀的属性Publisher,但可以通过以下几种方式实现类似的Combine监听管道:

方法1:利用自动生成的objectWillChange Publisher

@Observable宏会自动为类生成objectWillChange Publisher,它会在任意属性发生变化前发送事件。结合map和removeDuplicates可以精准监听目标属性的变化:

@Observable class Foo1 {
    var isEnabled = false
    private var cancellables = Set<AnyCancellable>()

    init() {
        objectWillChange
            // 捕获当前isEnabled的最新值
            .map { [weak self] in self?.isEnabled ?? false }
            // 过滤重复值,避免其他属性变化触发不必要的回调
            .removeDuplicates()
            .sink { print($0.description) }
            .store(in: &cancellables)
    }
}

注意:objectWillChange会响应类中所有属性的变化,所以必须用removeDuplicates确保只有isEnabled实际变化时才触发回调;使用[weak self]避免循环引用。

方法2:手动用CurrentValueSubject包裹属性

如果需要像@Published一样仅监听单个属性的变化,可以手动用CurrentValueSubject封装属性,在setter中发送事件:

@Observable class Foo1 {
    private let _isEnabled = CurrentValueSubject<Bool, Never>(false)
    var isEnabled: Bool {
        get { _isEnabled.value }
        set { _isEnabled.send(newValue) }
    }
    private var cancellables = Set<AnyCancellable>()

    init() {
        _isEnabled
            .map { $0 }
            .sink { print($0.description) }
            .store(in: &cancellables)
    }
}

这种方式和原来的@Published行为几乎一致,只是需要手动管理属性的get/set逻辑,适合需要精准控制单个属性监听的场景。

方法3:封装withObservationTracking为Combine Publisher

如果需要更灵活的监听逻辑,可以将Observation框架的withObservationTracking封装为Combine Publisher:

extension Publisher where Output == Void, Failure == Never {
    func track<Value, Object: Observable>(_ object: Object, keyPath: KeyPath<Object, Value>) -> AnyPublisher<Value, Never> {
        flatMap {
            Future { promise in
                withObservationTracking {
                    _ = object[keyPath: keyPath]
                } onChange: {
                    promise(.success(object[keyPath: keyPath]))
                }
            }
        }
        .eraseToAnyPublisher()
    }
}

// 使用示例
@Observable class Foo1 {
    var isEnabled = false
    private var cancellables = Set<AnyCancellable>()

    init() {
        Just(())
            .track(self, keyPath: \.isEnabled)
            .removeDuplicates()
            .sink { print($0.description) }
            .store(in: &cancellables)
    }
}

这种方式适合需要监听多个属性或自定义触发逻辑的场景,实现相对灵活。


内容的提问来源于stack exchange,提问作者Roland Lariotte

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.11 06:35:19