Say I have the following method inside a UIViewController
subclass:
- (void)makeAsyncNetworkCall { [self.networkService performAsyncNetworkCallWithCompletion:^{ dispatch_async(dispatch_get_main_queue(), ^{ [self.activityIndicatorView stopAnimating]; } }); }]; }
I know that the reference to self
inside the block results in the UIViewController
instance being retained by the block. As long as performAsyncNetworkCallWithCompletion
does not store the block in a property (or ivar) on my NetworkService
, am I right in thinking there is no retain cycle?
I realise this structure above will lead to the UIViewController being retained until performAsyncNetworkCallWithCompletion
finishes, even if it is released by the system earlier. But is it likely (or even possible?) the system will deallocate my UIViewController
at all (after the changes to the way iOS 6 manages a UIViewController
's backing CALayer
memory)?
If there is a reason I must do the "weakSelf/strongSelf dance", it would look like this:
- (void)makeAsyncNetworkCall { __weak typeof(self) weakSelf = self; [self.networkService performAsyncNetworkCallWithCompletion:^{ typeof(weakSelf) strongSelf = weakSelf; if (!strongSelf) { return; } dispatch_async(dispatch_get_main_queue(), ^{ [strongSelf.activityIndicatorView stopAnimating]; } }); }]; }
But I find this unconscionably ugly and would like to avoid it if it's not necessary.
As I believe you correctly diagnosed, using self
will not necessarily cause strong reference cycle in this scenario. But this will retain the view controller while the network operation completes, and in this case (as in most cases), there's no need to. Thus, it may not be necessary to do use weakSelf
, but probably prudent to do so. It minimizes the chance of an accidental strong reference cycle and leads to more efficient use of memory (releasing the memory associated with the view controller as soon as that view controller is dismissed rather than unnecessarily retaining the view controller until after the network operation is complete).
There is no need for the strongSelf
construct, though. You can:
- (void)makeAsyncNetworkCall { __weak typeof(self) weakSelf = self; [self.networkService performAsyncNetworkCallWithCompletion:^{ dispatch_async(dispatch_get_main_queue(), ^{ [weakSelf.activityIndicatorView stopAnimating]; }); }]; }
You only need the weakSelf
/strongSelf
combination where it's critical to have a strong reference (e.g., you're dereferencing ivars) or if you need to worry about race conditions. That does not appear to be the case here.
I think the issue is that the networkService may keep a strong reference to the block. And the view controller may have a strong reference to the networkService. So the possible cycle of VC->NetworkService->block->VC could exist. However, in this case, it's usually safe to assume that the block will be released after it has run, in which case the cycle is broken. So, in this case, it isn't necessary.
Where it is necessary is if the block is not released. Say, instead of having a block that runs once after a network call, you have a block that is used as a callback. i.e. the networkService object maintains a strong reference to the block and uses it for all callbacks. In this case, the block will have a strong reference to the VC, and this will create a strong cycle, so a weak reference is preferred.
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