出错代码

let btn: UIButton = UIButton()
btn.addAction {
    btn.isSelected = !btn.isSelected
    ...
}

退出这个页面的时候MLeaksFinder总是弹出弹窗说这个对象内存泄漏了,稍微研究了一下,发现btnUIControl互相持有了,造成循环引用。

addAction是一个扩展方法

class ClosureSleeve {
    let closure: () -> ()
    
    init(attachTo: AnyObject, closure: @escaping () -> ()) {
        self.closure = closure
        objc_setAssociatedObject(attachTo, "[\(arc4random())]", self, .OBJC_ASSOCIATION_RETAIN)
    }
    
    @objc func invoke() {
        closure()
    }
}

extension UIControl {
    func addAction(for controlEvents: UIControl.Event = .primaryActionTriggered, action: @escaping () -> ()) {
        let sleeve = ClosureSleeve(attachTo: self, closure: action)
        addTarget(sleeve, action: #selector(ClosureSleeve.invoke), for: controlEvents)
    }
}

解决方案

let btn: UIButton = UIButton()
btn.addAction { [unowned btn] in
    btn.isSelected = !btn.isSelected
    ...
}