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

弱引用Passthrough Subject无法发送数据的原因及疑问

问题:Combine中弱引用self时PassthroughSubject无法发送数据

我在使用Combine设计模式时遇到一个问题:在闭包中使用[weak self]弱引用时,PassthroughSubject无法向视图控制器发送数据,但改用强引用self就能正常接收。同时还有两个疑问:强引用是否会导致循环引用?为什么弱引用self时无法发送数据?

相关代码

弱引用self的ViewModel实现

import Foundation
import Combine

class ViewModel {
    
    var publisher = PassthroughSubject<[WebData], Never>()
    let apis : [ApiProtocol]
        
    init(apis: [ApiProtocol]){
        self.apis = apis
        getData()
    }
        
    func getData(){
        guard !apis.isEmpty else { return }
        apis.forEach {api in
            api.getApiData { [weak self] webData in
                self?.publisher.send(webData)
            }
        }
    }    
}

强引用self的ViewModel实现

func getData(){
    guard !apis.isEmpty else { return }
    apis.forEach {api in
        api.getApiData { webData in
            self.publisher.send(webData)
        }
    }
}

视图控制器DataVC代码

class DataVC: UIViewController {
    
    weak var viewModel : ViewModel?
    var models = [WebData]()
    
    var cancellable = [AnyCancellable]()
    
    @IBOutlet weak var tableView: UITableView!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        downloadData()
        tableView.delegate = self
        tableView.dataSource = self
    }
    
    func downloadData() {
        guard let model = viewModel else { return }
        model.publisher
            .receive(on: DispatchQueue.main)
            .sink { _ in

            } receiveValue: { [weak self] value in
                self?.models.append(contentsOf: value)
                DispatchQueue.main.async {
                    self?.tableView.reloadData()
                }
            }.store(in: &cancellable)
    }
}

补充说明

将DataVC中viewModel的声明从weak var viewModel : ViewModel?改为非弱引用的var viewModel : ViewModel!后,弱引用self的ViewModel代码可正常工作,但疑惑的是:为什么viewModel为弱引用时,即使通过guard-let解包后使用,仍无法正常工作?


问题分析与解答

1. 强引用self是否会导致循环引用?

不会。分析引用链:

  • ViewModel持有apis数组(强引用)
  • 每个Api实例持有回调闭包(强引用),闭包持有ViewModel的强引用
    但ViewModel并不持有这个回调闭包,当Api的异步请求完成后,Api实例会被释放,对应的闭包也会被释放,不会形成闭环的循环引用。不过从最佳实践来说,还是推荐使用[weak self]避免潜在的内存问题。

2. 弱引用self时无法发送数据的核心原因

问题出在视图控制器中对ViewModel的弱引用导致ViewModel提前被销毁:

  • 当DataVC中声明weak var viewModel: ViewModel?,如果ViewModel没有其他强引用持有者,那么在viewDidLoad执行完毕后,ARC会立即释放ViewModel实例。
  • 虽然downloadData里用guard let model = viewModel解包得到了ViewModel的引用,但这只是临时的强引用,方法执行完毕后这个引用就会消失,ViewModel还是会被销毁。
  • 当Api的异步回调触发时,[weak self]中的self已经是nil,self?.publisher.send(webData)不会执行,自然视图控制器收不到数据。

3. 改为非弱引用viewModel后正常的原因

当DataVC持有ViewModel的强引用(var viewModel: ViewModel!),ViewModel实例的生命周期会和DataVC绑定,不会被提前释放。Api异步回调触发时,[weak self]中的self仍然指向有效的ViewModel实例,publisher.send(webData)能正常执行,数据可以顺利发送到视图控制器的sink闭包中。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.17 16:45:08