Logs a memory leak caused by a recently-encountered circular reference

  • I almost didn’t recognize you because you changed your grammar, and I had to look for a long time
  1. Without further ado, let’s look at a piece of code
// The first part of the code here is a custom UIView, the view is a button, this view has an allSelectCallback, used to external calls when using 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? ()}}Copy the code
  1. Here’s the code to use the UIView above
Class Controller2: UIViewController {lazy var leakView:SomeView = {// Create the above Viewletview1 = SomeView.init(frame: CGRect.init(x: 100, y: 100, width: 100, height: Callback = {[weak self]} {[weak self]in
            view1.isHidden = trueself? .dismiss(animated:true, completion: nil)
        }
        return view1
    }()
    
     override func viewDidLoad() {
        
        super.viewDidLoad()
        view.addSubview(leakView)
        
    }
}
Copy the code
  1. I even use weak self when I return it. What’s the problem?
  2. But take a closer look at the lazily loaded code
  • The view holds an allSelectCallback attribute

  • In the allSelectCallback callback, view.ishidden is called

  • The closure captures a reference to the View and holds it, so a reference loop occurs

  • As with the previous oc solution, weak var WeakView = view can solve the problem outside

  • The [weak self] in the code only weakly references the view of the controller, so the controller can be released normally. What is really not released is SomeView, and the leaking point is here