使用@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
相关产品推荐
相关产品推荐

