You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Combine框架中PassthroughSubject运行无输出是什么原因?

错误原因

你的核心错误是创建订阅后立刻调用了.cancel(),直接终止了订阅关系,后续发送的所有事件都不会被已经取消的订阅者接收。

PassthroughSubject本身不会缓存任何历史事件,只有在订阅处于激活状态时,新发送的事件才会投递给订阅者。你在sink生成订阅的同一行就链式调用.cancel(),订阅刚创建就被立刻销毁,后续执行send("one")、send("two")、send("three")时,已经没有活跃的订阅者存在,自然不会有任何打印输出。


关于另外两个测试用例的说明

你写的序列Publishers、CurrentValueSubject测试代码同样存在立刻取消订阅的问题,只是二者的特性让你误以为代码正常运行:

  • 数组等序列类型的publisher是同步派发事件的:调用sink时,它会在sink方法返回前,就把所有元素、完成事件全部同步发送给订阅者,等链式调用执行到.cancel()时,所有事件已经派发完成,打印动作已经执行完毕,所以你能看到输出。
  • CurrentValueSubject会始终持有最新的一个值:调用sink订阅它的瞬间,它会先把当前保存的最新值同步推送给订阅者,这个动作同样发生在.cancel()执行之前,所以你能看到打印输出。但如果在调用.cancel()之后再执行send发送新值,一样无法被接收。

正确写法

你需要把sink返回的AnyCancellable订阅实例存储起来,不要立刻调用cancel,订阅会在持有它的实例销毁时自动取消,参考代码:

import UIKit
import Combine

class DemoViewController: UIViewController {
    // 用于存储所有订阅,只要当前控制器不被销毁,集合内的订阅就会保持激活
    var cancellables = Set<AnyCancellable>()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        let mySubject = PassthroughSubject<String, Error>()
        
        mySubject.sink(
            receiveCompletion: { completion in
                print("-- completion", completion)
            },
            receiveValue: { value in
                print("-- value", value)
            }
        )
        // 将订阅存入集合,不要立刻调用cancel
        .store(in: &cancellables)
        
        // 此时订阅处于激活状态,发送的事件可以被正常接收
        mySubject.send("one")
        mySubject.send("two")
        mySubject.send("three")
    }
}

注意:Combine 中所有订阅如果没有被强引用持有、或者被主动调用cancel,就会被立刻回收终止,不要在创建订阅的链式调用末尾直接写.cancel(),除非你明确需要立刻终止订阅。

内容的提问来源于stack exchange,提问作者Joakim Sjöstedt

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.26 13:51:45