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

使用Swift Combine的subscribe(_ subject:)方法时出现内存泄漏问题

Combine subscribe(_ subject:) API 内存泄漏问题解决方案

问题现象

使用Combine的subscribe<S>(_ subject: S) -> AnyCancellableAPI时,若Publisher经过eraseToAnyPublisher()包装,会导致持有AnyCancellable的对象(如示例中的SwiftViewController)无法正常释放,出现内存泄漏。示例代码如下:

class SwiftViewController: UIViewController {
    
    private var cancellable: AnyCancellable?
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        let subject1 = PassthroughSubject<(), Never>().eraseToAnyPublisher()
        let subject2 = PassthroughSubject<(), Never>()
        self.cancellable = subject1.subscribe(subject2)
    }
}

复现步骤:Push进入SwiftViewController后返回,该控制器实例未被释放,存在内存泄漏。测试环境:Xcode 15.2,iOS模拟器17.4。

泄漏原因

subscribe(_ subject:)方法内部,Subject会持有传入的Publisher引用;而当Publisher是被eraseToAnyPublisher()包装后的实例时,该包装对象会反向持有Subscription(Subscription又关联到Subject),形成循环引用。由于ViewController持有AnyCancellable,AnyCancellable又持有Subscription,最终导致ViewController无法被ARC回收。

解决方案

方案一:用sink替代subscribe(_ subject:)

通过sink接收Publisher事件并手动转发到Subject,打破循环引用:

class SwiftViewController: UIViewController {
    
    private var cancellable: AnyCancellable?
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        let subject1 = PassthroughSubject<(), Never>().eraseToAnyPublisher()
        let subject2 = PassthroughSubject<(), Never>()
        self.cancellable = subject1
            .sink(receiveValue: subject2.send)
    }
}

方案二:避免对Publisher使用eraseToAnyPublisher()(业务允许时)

如果无需隐藏Publisher的具体类型,可直接去掉eraseToAnyPublisher(),同样能避免循环引用:

class SwiftViewController: UIViewController {
    
    private var cancellable: AnyCancellable?
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        let subject1 = PassthroughSubject<(), Never>()
        let subject2 = PassthroughSubject<(), Never>()
        self.cancellable = subject1.subscribe(subject2)
    }
}

内容的提问来源于stack exchange,提问作者Yanni Wang

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.19 05:58:25