如何使用 class 方法作为闭包而不在 method/closure 中持有对 self 的强引用?

How to use a class method as a closure without holding a strong reference to self in that method/closure?

我有一个 class :

class myVC:UIViewController {
    let myButton = MyButton()
    func viewDidLoad() 
    {
         view.addSubview(myButton)
         myButton.addTarget(myMethodClosure) // ***
    }

    func myMethodClosure() // I guess this method captures self strongly when im using it as a closure, tell me if im wrong 
    {
        self.doingStuffs() 
    }
}

我的按钮 Class :

class MyButton:UIView {
    var cbk:(()->Void)?
    init() 
    {
        // ... 
        addTapGestureRecognizer(#selector(onPress)) 
    }
    func addTarget(_ cbk:()->Void))
    {
        self.cbk = cbk
    }
    func onPress() {
        // execute animation of the button 
        // ... and after it :  
        self.cbk?() 
    }
}

当我呈现 myVC 然后在之后将其关闭时,VC 不会被释放。我想这是因为 myMethodClosure,就像在线 *** 上的闭包(不是方法)一样,对 self(即:myVC)有很强的引用。 所以它变成了:

rootview -> myVC -> myButton -> myMethodClosure(held in variable cbk)
              ^                        |
              |                        | 
              --------------------------

因此,由于我的VC 有 2 个引用,当 rootview 使用 rootview.dismiss()

释放对它的引用时,它不会被释放

我的问题是:当我将方法作为闭包线传递时 //***,怎么说 "I want to pass it like a closure, but holding a weak reference to self" 我试过了:myButton.addTarget([weak self] myMethodClosure)当然没用...

像往常一样,通过消除所有不必要的渣滓来了解这里发生了什么是最简单的。这是您正在执行的操作的简化版本:

class MyVC:UIViewController {
    let myButton = MyButton()
    override func viewDidLoad() {
        view.addSubview(myButton)
        myButton.cbk = myMethodClosure
    }
    func myMethodClosure() {
        print(self)
    }
    deinit {
        print("deinit")
    }
}
class MyButton:UIView {
    var cbk:(()->Void)?
}

我们可以通过说

来测试
let what = MyVC()
what.loadViewIfNeeded()

在那一点上,what 不存在了,但是 "deinit" 没有被打印出来。我们有一个保留周期。 MyVC 实例通过 myButton 强引用了 MyButton 实例,但是 MyButton 实例强引用了它的 cbk 函数,该函数强引用了 MyVC 实例(因为该函数引用 self).

打破循环的方式多种多样,但是如果想在函数层面进行,需要将函数表达为匿名函数,这样才能发挥作用[weak self] :

myButton.cbk = { [weak self] in self?.myMethodClosure() }

可能真的没有任何很好的理由说明为什么一个函数有一个名字(即由 func 定义)不能有一个捕获列表,但目前 Swift 没有规定这样做。