Swift Combine中CombineLatest总是触发两次的问题求助
问题根因与修复方案
常见触发原因
- 中央控制器重复实例化:订阅逻辑写在
init方法中,如果控制器被多次创建,会生成多份独立订阅,同一事件触发时所有订阅的闭包都会执行 - 上游发布者重复发送相同值:
CurrentValueSubject不会自动判断值是否变化,只要调用send就会向下游发布数据,即使值和当前存储的最新值完全一致 CombineLatest的多上游触发特性:如果短时间内先后修改了两类参数,CombineLatest会被触发两次,若两次最终组合值完全相同,即便经过debounce也会输出两次相同结果
修复步骤
排查重复订阅问题
在控制器init方法中添加打印日志,确认初始化次数。如果控制器被多次实例化,可将控制器改为单例模式,保证全局只有一份订阅。为组合流添加去重逻辑
在CombineLatest之后、debounce之前添加removeDuplicates操作符,仅当两次输出的参数组合不同时才向下游传递,需要你的参数模型遵守Equatable协议:
Publishers .CombineLatest( InteractionParameters.sharedInstance.influenceParameters, InteractionParameters.sharedInstance.steeringParameters ) .removeDuplicates() .debounce(for: 0.3, scheduler: DispatchQueue.main) .sink { (influencing, steering) in print("influencing params: \(influencing), steering: \(steering)") } .store(in: &subscriptions)
如果参数模型未实现Equatable,可自定义去重判断逻辑:
.removeDuplicates { pre, current in // 自定义判断两组参数是否完全相等的逻辑 pre.0.xxx == current.0.xxx && pre.1.yyy == current.1.yyy }
- 上游发布者单独去重(可选)
如果上游存在频繁发送相同值的场景,可以直接给每个CurrentValueSubject单独添加去重逻辑,减少无效的信号传递:
// 声明Subject时直接追加去重操作 let influenceParameters = CurrentValueSubject<InfluenceType, Never>(initialValue) .removeDuplicates() .eraseToAnyPublisher()
内容的提问来源于stack exchange,提问作者jbm
相关产品推荐
相关产品推荐

