如何通过反射获取Swift ObservableObject的@Published属性?
实现自定义
@Observed属性包装器监听@Published属性变化 我需要实现一个类似@ObservedObject的属性包装器@Observed,用来监听遵循ObservableObject协议的类中@Published属性发出的Combine事件,把所有sink处理逻辑封装在Swift包里,不用在主代码库中管理。目前的问题是,如何通过反射识别@Published属性,并订阅这些属性的事件。
我的目标是构建类似SwiftUI的Combine响应式架构,当被包装的ObservableObject的@Published属性变化时,执行模型序列化等操作,而非更新界面。我想搞清楚SwiftUI如何感知子模型更新并触发重绘,认为通过反射在根层级获取子对象的所有属性并订阅,就能实现这类响应式架构。
现有代码示例:
@propertyWrapper struct Observed<T> where T : ObservableObject { var sinks = [AnyCancellable]() var wrappedValue: T init(wrappedValue: T) { self.wrappedValue = wrappedValue let mirror = Mirror(reflecting: wrappedValue) for case let (label?, value) in mirror.children { //if `value` is wrapped as an `@Published` property { // grab sink to the property //} } } }
解决方案代码
import Combine @propertyWrapper struct Observed<T> where T : ObservableObject { private var sinks = Set<AnyCancellable>() var wrappedValue: T init(wrappedValue: T) { self.wrappedValue = wrappedValue let mirror = Mirror(reflecting: wrappedValue) // 遍历所有属性,筛选并订阅@Published属性 for case let (label?, value) in mirror.children { guard let published = value as? AnyPublished else { continue } published.publisher .sink { [weak self] _ in guard let self = self else { return } self.handlePropertyChange(for: label) } .store(in: &sinks) } // 订阅对象级别的变更通知(类似SwiftUI的重绘触发逻辑) wrappedValue.objectWillChange .sink { [weak self] _ in self?.handleObjectWillChange() } .store(in: &sinks) } // 单个属性变更的处理逻辑(替换成你的序列化等操作) private func handlePropertyChange(for propertyName: String) { print("属性\(propertyName)已变更,执行模型序列化") // 这里添加你的自定义业务逻辑 } // 对象整体变更的处理逻辑 private func handleObjectWillChange() { print("对象即将发生变更") // 可选:添加对象级别的统一处理逻辑 } } // 辅助协议,用来擦除Published的具体值类型 private protocol AnyPublished { var publisher: AnyPublisher<Void, Never> { get } } extension Published: AnyPublished { var publisher: AnyPublisher<Void, Never> { projectedValue .map { _ in () } .eraseToAnyPublisher() } }
关键说明
- 识别
@Published属性:通过AnyPublished协议擦除Published的具体值类型,统一处理不同类型的@Published属性,再通过反射筛选出符合条件的属性。 - SwiftUI的底层逻辑:SwiftUI并没有逐个订阅
@Published属性,而是通过监听ObservableObject的objectWillChangepublisher实现视图重绘——所有@Published属性的变更都会自动触发objectWillChange发送事件。如果你的场景只需要在对象变更时执行统一操作,直接订阅objectWillChange会更高效;如果需要针对单个属性做差异化处理,再用上述逐个订阅的方式。 - 内存管理:用
Set<AnyCancellable>存储订阅引用,确保订阅生命周期和Observed实例一致,避免内存泄漏。
内容的提问来源于stack exchange,提问作者mjKosmic
相关产品推荐
相关产品推荐

