传递方法而不是闭包时会发生保留循环
Retain cycle happens when passing method instead of closure
在 Swift 中,我们可以使用 ObjC 中没有的功能:可以在任何需要使用闭包的地方使用方法。但它会导致保留循环。看这个例子:
import Foundation
class C1 {
let closure: Void -> Void
init(closure: Void -> Void) {
self.closure = closure
}
deinit {
print("C1 deinit")
}
}
class C2 {
var c1: C1!
func initializeC1() {
c1 = C1(closure: f)
}
func f() {}
deinit {
print("C2 deinit")
}
}
func main() {
let c2 = C2()
c2.initializeC1()
}
main()
这里我们创建了循环 C2 -> C1 -> f -> C2。如果你 运行 这个程序, deinit
将不会被调用。但是如果把initializeC1
里面的f
换成{}
,比如说就是
对于常规闭包,我们可以使用捕获列表来避免强保留,但看起来您不能将它们用于方法。
所以,问题是:在这种情况下我们如何打破保留循环,这有可能吗?
当然,我们可以 "weakify" 像这样将绑定方法包装在闭包中:
import Foundation
class C1 {
let closure: Void -> Void
init(closure: Void -> Void) {
self.closure = closure
}
deinit {
print("C1 deinit")
}
}
class C2 {
var c1: C1!
func initializeC1() {
// HERE we wrap a method call into a closure to break retain-cycle.
c1 = C1(closure: { [weak weakSelf = self] in
weakSelf?.f()
})
}
func f() {}
deinit {
print("C2 deinit")
}
}
func main() {
let c2 = C2()
c2.initializeC1()
}
main()
//C2 deinit
//C1 deinit
在 Swift 中,我们可以使用 ObjC 中没有的功能:可以在任何需要使用闭包的地方使用方法。但它会导致保留循环。看这个例子:
import Foundation
class C1 {
let closure: Void -> Void
init(closure: Void -> Void) {
self.closure = closure
}
deinit {
print("C1 deinit")
}
}
class C2 {
var c1: C1!
func initializeC1() {
c1 = C1(closure: f)
}
func f() {}
deinit {
print("C2 deinit")
}
}
func main() {
let c2 = C2()
c2.initializeC1()
}
main()
这里我们创建了循环 C2 -> C1 -> f -> C2。如果你 运行 这个程序, deinit
将不会被调用。但是如果把initializeC1
里面的f
换成{}
,比如说就是
对于常规闭包,我们可以使用捕获列表来避免强保留,但看起来您不能将它们用于方法。 所以,问题是:在这种情况下我们如何打破保留循环,这有可能吗?
当然,我们可以 "weakify" 像这样将绑定方法包装在闭包中:
import Foundation
class C1 {
let closure: Void -> Void
init(closure: Void -> Void) {
self.closure = closure
}
deinit {
print("C1 deinit")
}
}
class C2 {
var c1: C1!
func initializeC1() {
// HERE we wrap a method call into a closure to break retain-cycle.
c1 = C1(closure: { [weak weakSelf = self] in
weakSelf?.f()
})
}
func f() {}
deinit {
print("C2 deinit")
}
}
func main() {
let c2 = C2()
c2.initializeC1()
}
main()
//C2 deinit
//C1 deinit