Swift Combine:prepend()前置share()导致初始sink执行被阻止?
我搭建了如下类似Playground示例的发布者结构:
import Combine let sub1 = PassthroughSubject<String, Never>().prepend("initial 1")//.share() let sub2 = PassthroughSubject<String, Never>().prepend("initial 2") Publishers.CombineLatest(sub1, sub2).sink { content1, content2 in print("combined received: \(content1) and \(content2)") } sub1.sink { content1 in print("first received: \(content1)") } sub2.sink { content2 in print("second received: \(content2)") }
当sub1后的share()被注释时,控制台输出如下:
combined received: initial 1 and initial 2 first received: initial 1 second received: initial 2
这符合预期。但启用share()后,输出变为:
combined received: initial 1 and initial 2 second received: initial 2
在Xcode项目中,我使用prepend()触发初始执行,但share()阻止了部分链式调用的初始执行。请问这是预期行为吗?
这是预期行为,核心原因在于share()的工作机制:
默认情况下,
prepend返回的发布者属于冷发布者,每个新订阅者都会触发一次完整的上游订阅流程,包括prepend中初始值的发送。因此未添加share()时,sub1的两个订阅(CombineLatest和单独的sink)都能收到initial 1。添加
share()后,发布者转为共享型发布者,它会复用同一份上游订阅的事件流。share()的默认逻辑是:仅在第一个订阅者发起订阅时触发上游订阅,且只向订阅者发送订阅之后产生的事件。
对应你的代码执行流程:
- 第一个订阅
CombineLatest(sub1, sub2)触发了带share()的sub1的上游订阅,此时prepend("initial 1")将初始值发送给了这个订阅者。 - 后续为
sub1添加第二个sink订阅时,share()的发布者已经完成了初始值的发送,不会向新订阅者重发历史事件,因此这个sink收不到initial 1。
如果希望新订阅者也能获取到之前的初始值,可以使用share(replay: 1)替代默认的share(),它会缓存最近1个事件并发送给后续订阅者。修改后的代码如下:
let sub1 = PassthroughSubject<String, Never>().prepend("initial 1").share(replay: 1)
此时第二个sink也能收到initial 1,输出会和未添加share()时一致。
内容的提问来源于stack exchange,提问作者jns_ai_unr
相关产品推荐
相关产品推荐

