Can anyone please explain why this doesn't leak?
I'm capturing self
within a closure
so I would have two strong pointers pointing at each other, therefore, the deinit
message shouldn't ever be called for the Person object.
First, this is my class Person:
class Person {
var name: String
init(name: String) { self.name = name }
deinit { print("\(name) is being deinitialized") }
}
And this is my ViewController's implementation:
class ViewController: UIViewController {
var john:Person?
func callClosureFunction( closure:(name:Bool) -> () ) {
closure(name: true)
}
override func viewDidLoad() {
super.viewDidLoad()
john = Person(name:"John")
self.callClosureFunction { (name) in
self.john?.name = "John Appleseed"
self.john = nil
// xcode prints - John Appleseed is being deinitialized
}
}
}
I was expecting to be able to fix the issue by doing:
self.callClosureFunction { [weak self] (name) in ...
But that wasn't even necessary. Why?
Since your view controller is not retaining the closure, there is no circular reference. If you wrote this:
class ViewController: UIViewController {
var john:Person?
var closure:(Bool)->()?
func callClosureFunction( closure:((name:Bool) -> ())? ) {
closure?(name: true)
}
override func viewDidLoad() {
super.viewDidLoad()
john = Person(name:"John")
closure = { (name) in
self.john?.name = "John Appleseed"
// Because this closure will never be released, the instance of Person will never deinit either
}
self.callClosureFunction(closure)
}
}
then the view controller would retain the closure and the closure would retain the view controller via its reference to self
. Therefore, neither would be released, and if you don't explicitly set self.john = nil
(which you did in your original example), then the Person
instance would never get deninit
called.
It's quite common to inappropriately use weak self
in closures when not necessary (and this can actually lead to some obscure bugs). The key rule to remember is that weak references are not the default in general under ARC. Strong should be the default unless it would lead to a retain cycle, in which case weak should be used only to break that circular reference. Same for closures: strong self
should be the default, unless the self
in this case also has a strong reference to the closure itself.