Hi there, this is my first time posting here. I've heard that some of the apple developers are usually active on these forums, so I've decided to shoot my shot, because this question was driving me crazy for a few days now and nobody could yet give me a clear view on what's actually happening. Here is the first snippet of the code
class Animal {
var name = "Fischer"
var command: () -> Void = { }
deinit {
print(#function, #line)
}
}
do {
var pet: Animal? = Animal()
pet?.command = { print(pet?.name ?? "Bobby") }
}
This code causes a memory leak, because
-
Reference 'pet' is created.
-
Independent copy of the reference 'pet' is created inside the closure. now there are two references to the same object, which are 'pet' outside the closure and 'pet' inside the closure.
-
As we exit the 'do' scope, the 'pet' reference is deleted, but ARC does not deallocate the object due to the strong reference 'pet', that is still referencing to the same object.
And all of that causes a memory leak. Now here is the code, that is pretty similar, except for the fact, that we assign a nil to the 'pet' reference
class Animal {
var name = "Fischer"
var command: () -> Void = { }
deinit {
print(#function, #line)
}
}
do {
var pet: Animal? = Animal()
pet?.command = { print(pet?.name ?? "Bobby") }
pet = nil
}
And boom! deinit is called, meaning that the object was deallocated, but how? Why was the object deallocated? If we are deleting the exact same reference, that was deleted by the end of the 'do' scope in the first snippet? Am I misunderstanding something? I really hope this post will find the right people, since I could not even find appropriate tags for that.
I've heard that some of the apple developers are usually active on these forums
That’s true. I also want to make sure you’re aware of Swift Forums. If you have questions about Swift the language, rather than some Apple API, that’s a great place for them.
But I’m happy to answer Swift questions here too; it keeps me in practice (-:
Regarding your specific issue, the reason why your second example deallocates immediately when you set pet
to nil
is that the closure captures the pet
variable, not the object it points to. So let’s come back to this:
Independent copy of the reference pet is created inside the closure. now there are two references to the same object, which are 'pet' outside the closure and 'pet' inside the closure.
No, that’s not right. It’d be better to say that:
An independent reference to the pet
variable is captured by the closure. There is a single references to the same object stored in the pet
variable, but there are multiple references to that pet
variable.
Consider this:
func main() {
var counter = 0
let c = {
counter += 1
}
print(counter) // 0
c()
print(counter) // 1
}
main()
Note how the closure has captured a reference to counter
. That’s analogous to what’s going on in your example. That is, pet
isn’t the object, it’s a variable that references the object, and closures can capture references to such variables.
Share and Enjoy
—
Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"