Reputation: 1078
I'm experimenting with memory management in Swift by following.
class Person {
let name: String
//var block: (() -> Void)?
init(name: String) {
self.name = name
}
// Declare variable clone, using self inside.
private lazy var clone: String = {
return self.name
}()
deinit {
print("Destroying \(name)")
}
func doSomething() {
print("Doing something for \(name)")
}
}
var p2: Person? = Person(name: "p2")
print(p2!.clone)
p2 = nil
As you see, I'm using self
inside when declaring a lazy var and I think it is still ok because when p2 is getting nil, I can see the deinit
method get called.
However, if I make a change like following
// This is a closure
private lazy var clone: () -> String = {
return self.name // leaking memory is here
}
Now, I am getting a leaking memory.
My question is for a variable using lazy instantiation, why I don't get a leaking memory even though I am using self
.I thought I had to use it otherwise I would get a leaking memory.
Upvotes: 3
Views: 2625
Reputation: 3878
Here :
private lazy var clone: () -> String = {
return self.name // leaking memory is here
}
You are assigning the closure itself to the variable, instead of assigning the String
that it is supposed to return. And since you're using self
which the closure retains, the two will never be released which can lead to a memory leak
. A reference cycle
is created as the closure is retained as a property and the closure retains self. Here is where the capture lists
come into picture. You can fix the leak like so:
private lazy var clone: () -> String = { [unowned self] in
return self.name // leaking memory is fixed
}
Self
is declared as unowned
in the capture lists
as it is safe to assume that it will NOT be nil
at any point. If you are sure the variable will NEVER be nil
, use unowned
but if you think at some point it might become nil
, use weak
instead.
Upvotes: 7
Reputation: 4218
The reason you leak memory is because closure will capture self strongly in default and at the same time self hold the closure as a property strongly. It has nothing to do with lazy variable.
Upvotes: 1