In Swift we can nice feature we didn't have in ObjC: it's possible to use a method everywhere you would use a closure. But it can lead to retain cycles. Look at this example:
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()
Here we created cycle C2 -> C1 -> f -> C2. If you run this program, deinit
won't be called. But if you replace f
in initializeC1
to {}
, for example, it will be.
For regular closures we can use capture lists to avoid strong retaining but it looks like you can't use them for methods. So, the question is: How could we break retain cycle in such situation and is it possible at all?
Surely, we can "weakify" a bound method by wrapping it in closure like so:
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