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

Swift Combine闭包中self的weak与unowned正确使用方式

在Swift Combine闭包中正确使用self的指南

先看你的代码问题

直接在filter闭包里使用self.nextPageAvailabe会触发强引用循环:ViewModel持有subscriptions集合,订阅对象(AnyCancellable)存在这个集合里;而filter闭包捕获了self,订阅对象又持有这个闭包,最终形成self → subscriptions → 订阅 → 闭包 → self的循环,导致ViewModel无法被释放,引发内存泄漏。

[weak self] vs [unowned self]的选择逻辑

两者都是为了打破强引用循环,但适用场景完全不同:

1. 优先用[weak self]的场景

当你无法保证self的生命周期一定长于闭包时,比如ViewModel可能在订阅未取消前就被销毁(比如页面被回收),必须用weak self。它是可选类型,不会导致崩溃,需要在闭包里处理self为nil的情况。

示例代码:

requestPublisher
    .filter { [weak self] _ in
        // 如果self已释放,直接过滤掉事件
        self?.nextPageAvailabe ?? false
    }
    .sink(receiveValue: {
        print("Received request")  
    })
    .store(in: &subscriptions)

如果闭包里需要多次访问self,可以在开头做可选绑定,避免重复写可选链:

.sink(receiveValue: { [weak self] _ in
    guard let self = self else { return }
    // 这里可以直接用self,不用处理可选
    print("Next page available: \(self.nextPageAvailabe)")
})

2. 仅在确定安全时用[unowned self]

当你能100%保证self的生命周期一定长于闭包时,才适合用unowned self。它是非可选类型,如果self提前释放,访问它会直接崩溃。

在你的ViewModel场景里,订阅存在subscriptions集合中,而这个集合是ViewModel的属性——只要ViewModel存在,订阅就存在;ViewModel销毁时,subscriptions会被清空,订阅也会被取消。这种情况下可以安全使用unowned self:

requestPublisher
    .filter { [unowned self] _ in
        self.nextPageAvailabe
    }
    .sink(receiveValue: {
        print("Received request")  
    })
    .store(in: &subscriptions)

Combine中使用self的通用原则

  • 只要闭包会被订阅对象保留(比如filter、map、sink的闭包),就必须考虑打破强引用循环,要么用weak/unowned,要么确保订阅会被及时取消(比如用store(in:)绑定到ViewModel的属性,依赖ViewModel销毁时自动释放)。
  • 不确定生命周期时,一律用[weak self],这是最安全的选择。
  • 如果闭包不需要访问self的属性/方法,完全可以不用捕获self。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.15 16:15:26