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
相关产品推荐
相关产品推荐

