记录一个最近遇到的循环引用导致的内存泄漏
- 小样儿 你换了个语法我差点不认识你了,害我找老半天
- 骚话不多说,让我们来看一段代码把
//代码的第一部分 这里是一个自定义的UIView,view上就一个按钮,这个view有一个allSelectCallback 回掉,用来给外部调用的时候使用
class SomeView: UIView {
var allSelectCallback: (() -> Void)?
override init(frame: CGRect) {
super.init(frame: frame)
let btn = UIButton.init(frame: bounds)
addSubview(btn)
btn.addTarget(self, action: #selector(callBack), for: .touchUpInside)
}
@objc func callBack() {
allSelectCallback?()
}
}
- 下面是使用上面这个UIView的代码
class Controller2: UIViewController {
lazy var leakView:SomeView = {
//创建上面这个View
let view1 = SomeView.init(frame: CGRect.init(x: 100, y: 100, width: 100, height: 100))
//view 里面的按钮点击的时候让view隐藏
view1.allSelectCallback = { [weak self] in
view1.isHidden = true
self?.dismiss(animated: true, completion: nil)
}
return view1
}()
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(leakView)
}
}
- 是不是看上去完全没毛病啊,甚至在回掉里面还用了weak self,哪里有内存泄漏,你丫逗我呢?
- 但是再仔细看看懒加载中的代码
-
view 持有一个allSelectCallback属性
-
而在这个allSelectCallback的回掉中,调用了view.isHidden
-
这个闭包对view的引用进行了捕获,从而对view进行了持有,所以出现了引用循环
-
和以前用oc的时候的解决方案一样,在外面 weak var weakview = view 就可以解决问题了
-
代码中的 [weak self] 仅仅是弱引用了controller的view ,所以controller 可以正常释放,真正没有释放掉的是 SomeView,泄漏的点在这里