如何使用 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 没有规定这样做。
我有一个 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 没有规定这样做。