iOS 17中@Observable宏下Combine订阅变量的方法咨询
解决@Observable宏下Combine订阅属性变化的问题
迁移到@Observable宏后无法使用$myVariable的核心原因是:@Observable基于Observation框架实现,和@Published(Combine原生发布机制)的投影逻辑完全不同——@Published的$前缀返回Combine Publisher,而@Observable的$前缀仅在SwiftUI视图中用于生成Binding,并非Combine Publisher。
要继续用Combine订阅并响应属性变化,可通过以下两种方式实现:
方式一:订阅对象的整体属性变化
@Observable生成的类会自动附带objectWillChange属性(类型为ObservableObjectPublisher,属于Combine),可通过它监听对象所有属性的变化:
import Observation import Combine @Observable class MyModel { var myVariable = 0 } // 订阅示例 let model = MyModel() var cancellables = Set<AnyCancellable>() model.objectWillChange .sink(receiveValue: { _ in print("myVariable 已更新为:\(model.myVariable)") }) .store(in: &cancellables) // 触发属性变化 model.myVariable = 10
如果只关心特定属性的变化,可在sink回调里对比属性的新旧值做过滤。
方式二:订阅单个属性的精准变化
若需要仅监听特定属性的变动,可结合withObservationTracking为目标属性创建专属的Combine Publisher:
import Observation import Combine @Observable class MyModel { var myVariable = 0 // 为myVariable生成专属Combine Publisher var myVariablePublisher: AnyPublisher<Int, Never> { let subject = PassthroughSubject<Int, Never>() // 启动属性跟踪 let observationCancellable = withObservationTracking { // 必须显式访问目标属性,触发观察逻辑 subject.send(self.myVariable) } onChange: { subject.send(self.myVariable) } // 绑定生命周期,避免观察提前失效 return subject .handleEvents(receiveCancel: { observationCancellable.cancel() }) .eraseToAnyPublisher() } } // 订阅示例 let model = MyModel() var cancellables = Set<AnyCancellable>() model.myVariablePublisher .sink(receiveValue: { newValue in print("myVariable 更新为:\(newValue)") }) .store(in: &cancellables) // 触发属性变化 model.myVariable = 20
额外说明
在SwiftUI视图中,@Observable类的属性依然可以用$前缀生成Binding(比如TextField("", text: $model.myVariable)),但这个$仅用于视图绑定逻辑,和Combine Publisher无关。
内容的提问来源于stack exchange,提问作者Jon Vogel
相关产品推荐
相关产品推荐

