I have a question regarding memory deallocation and blocks/closures.
Following is the Swift method
self!.dismissViewControllerAnimated(false, completion: {
println(self);
})
Or the objective C method
[self dismissViewControllerAnimated:NO completion:^{
NSLog("%@",self);
}];
I would really appreciate if anyone could explain when in the above method self would be deallocated . Is it after the completion block is run or before that? I understand its taken care by ARC but I would like to know if self gets release message in the completion block or after that. Hence, if I do some minor clean up in the completion block (accessing self), is that safe/acceptable or not?
When it comes time to dismiss a presented view controller, the preferred approach is to let the presenting view controller dismiss it. In other words, whenever possible, the same view controller that presented the view controller should also take responsibility for dismissing it.
You can't remove a view controller from within itself (i.e. viewDidDisappear) - what you need to do is to remove all references to it, at which point ARC will deallocate it.
There are really two separate questions to understand the answer completely:
You can think of a closures as just another type (in Swift they really are). Every closure creates a strong ownership over the variables referenced inside of it, including self
. This ensures that you never reference a variable that has been deallocated. Just like in any other object, when the closure gets deallocated, it releases its ownership over all of its variables.
If the closure is the only thing with a strong reference to that a variable, the variable will be dealloced when the closure is dealloced.
So in short, variables stay in memory as long as the closure is still in memory.
Now the second part of this that is important to understand, is when does a closure get dealloced. You could store a closure in a variable:
func myMethod() {
var myClosure = {
println(self)
}
myClosure()
}
In this case, the closure has a strong reference from its variable myClosure
and the closure has a strong reference to self
. As soon as myClosure
goes out of scope, i.e. when myMethod
exits, it will be dealloced. When that happens, self will be released.
You may also have a situation, like in your question, where you are passing a closure into another method. In this case, the method you are passing the closure into is capturing a strong reference to your closure. When that method exits, it will release your closure, the closure will be deallocated, and it will release all variables captured inside it.
Sometimes it is necessary to define a closure that does not take ownership over a variable. You would do this to avoid circular references. You can read more in Apple's documentation on what a circular reference is and how to prevent them here. However, it is important to realize that unless you put in explicit effort (and code), closures will always capture strong references to variables referenced inside of it.
In Swift, while developing/debugging and trying to understand the timing of operations, you can add the following to your View Controllers (or any class), to track if or when the instance is a about to deallocated.
Although that won't help you detect 'strong reference cycles' described here:
https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/AutomaticReferenceCounting.html
deinit {
println(__FUNCTION__, "\(self)")
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With