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

Swift3中如何解决闭包引发的内存泄漏问题

修复闭包内存泄漏:使用weak self的安全方案

首先咱们先拆解内存泄漏的根源:你这里形成了循环引用链——friendsVC持有app.cri(CR类的实例),CR类通过CRBlock属性强引用了你传入的闭包,而闭包又强引用了friendsVC(通过代码里的self)。这三者互相持有,ARC无法自动回收任何一个对象,最终导致内存泄漏。

接下来解决你最关心的问题:用weak self还是unowned self?

  • unowned self只适合你能100%确定闭包执行期间,self(也就是friendsVC)绝对不会被销毁的场景。但如果用户在请求处理完成前就退出了这个页面(比如返回上一级VC),此时self已经被释放,再访问unowned self会直接触发崩溃,风险极高。
  • weak self是可选类型,当self被销毁后会自动变为nil,你可以在闭包里先判断self是否存在再执行后续操作,安全性拉满。显然你的场景(页面可能被提前退出)更适合用weak self。

修复后的代码

首先修改friendsVC里的闭包调用,添加weak self捕获列表,并安全访问self:

class friendsVC: UIViewController, UITextFieldDelegate {
    override func viewDidLoad() {
        super.viewDidLoad()
        self.app.cri?.AllSBFriends(handler: { [weak self] (SBfriendsUIDs, error) in
            guard let self = self else { return } // 安全解包,确保self存在再执行后续逻辑
            if error == nil {
                // Do something with list
            } else {
                self.friendsCountLbl.text = "Friends \(0)"
            }
        })
    }
}

另外,建议优化CR类的CRBlock处理:如果这个闭包只需要执行一次,调用完成后立即将CRBlock置为nil,避免它长期持有闭包引用(哪怕已经用了weak self,及时清理也是更严谨的做法):

class CR: NSObject {
    var CRBlock: ((Array<SBUserModel>?, Error?) -> ())?
    
    func GetAllSBUser(handler:@escaping (Array<SBUserModel>?, Error?) -> ()) {
        CRBlock = handler
        if self.AllUSersModels.count > 0 {
            self.CRBlock?(self.AllUSersModels, nil)
            self.CRBlock = nil // 调用完立即释放闭包引用
        } else {
            self.CRBlock?(nil, err)
            self.CRBlock = nil // 同样调用后置空
        }
    }
}

额外提醒

如果闭包逻辑比较复杂,用[weak self]配合guard let提前退出,能避免嵌套过多的可选绑定,让代码更整洁。永远不要轻易用unowned self,除非你能绝对保证self的生命周期一定长于闭包,否则崩溃风险不可控。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 06:53:59