RxSwift如何监听数组内元素的成员属性变更事件?
解决方案
BehaviorRelay仅在自身存储的value发生变更时才会发射事件。你存储的[Dog]是引用类型数组,修改数组中某一个Dog实例的内部属性,并不会改变数组元素的引用地址,所以dogs本身不会触发事件。
核心实现代码
import RxSwift import RxCocoa // 全局持有DisposeBag,防止订阅提前释放 let disposeBag = DisposeBag() dogs .flatMapLatest { dogs in // 合并当前数组中所有Dog的age可观察序列 Observable.combineLatest(dogs.map { $0.age.asObservable() }) // 任意age变更时返回最新的完整狗狗数组 .map { _ in dogs } // 首次订阅立刻触发一次回调,保证初始UI加载 .startWith(dogs) } // 切到主线程执行UI操作 .observe(on: MainScheduler.instance) .subscribe(onNext: { [weak self] latestDogs in // latestDogs就是最新的完整狗狗数组,可直接作为tableView数据源 self?.tableView.reloadData() }) .disposed(by: disposeBag)
逻辑说明
flatMapLatest:每次dogs数组本身发生增删元素的变更时,会自动取消旧数组的内部监听,重新对新数组的所有Dog实例的age属性做监听,避免内存泄漏和无效订阅combineLatest:将数组中所有Dog的age可观察序列合并,只要任意一个Dog的age发生变更,就会触发回调map { _ in dogs }:不管是数组变更还是age变更,外部订阅最终都能拿到最新的完整狗狗数组,方便直接赋值给tableView的数据源observe(on: MainScheduler.instance):确保UI刷新操作在主线程执行,避免崩溃
扩展提示
- 如果Dog类还有其他需要监听的属性,只要把每个实例的多个属性用
combineLatest合并即可,比如需要同时监听age和name,就把内部的$0.age.asObservable()替换为Observable.combineLatest($0.age.asObservable(), $0.name.asObservable()) - 如果不需要全量刷新tableView,也可以在拿到变更后自行计算diff,只刷新变更的行,性能更好
内容的提问来源于stack exchange,提问作者iago849
相关产品推荐
相关产品推荐

