0

I am trying to understand this code :

__weak LoginViewController *weakSelf = self;

NSTimer *networkTimer = [NSTimer pym_scheduledTimerWithTimeInterval:15.0 block:^{
    LoginViewController *strongSelf = weakSelf;
    [strongSelf timeout];
} repeats:NO];

[PYMAuthManager loginWithUsername:username password:password completionHandler:^(BOOL successful) {
    if (successful) {
        [networkTimer invalidate].......

it's for a network timer, that will timeout after 15 seconds if no activity. Why is the pointer *strongSelf = weakSelf created in the block? Is it not okay just to use [weakSelf timeout]? I understood that whenever accessing self in a block we have to use a weak reference, why is another pointer created here? Any help would be great, thank you.

Michał Ciuba
  • 7,876
  • 2
  • 33
  • 59
Kex
  • 8,023
  • 9
  • 56
  • 129
  • Turn warnings on, and the compiler will tell you. And you can't just learn simple rules, you need to understand what a weak reference is for these rules to be applied _intelligently_ and for them to make sense. – gnasher729 Jan 20 '15 at 16:31

1 Answers1

5

Edit: Updated to better reflect actual system semantics (as pointed out by Darren).

By using weakSelf in the block, you are avoiding retain cycles. If you were to replace the block code with [weakSelf timeout], there would be no difference; the object is retained for the duration of the timeout execution.

If you had instead used __unsafe_unretained to create your weakSelf, it's possible that the machine could release the memory back to the system and cause your app to EXC_BAD_ACCESS while executing timeout. Creating a strong reference in this instance would avoid this error.


When you create a strong reference, it is held within its scope; in this case, for the duration of the block. Because your block only effectively executes one statement, the replacement to [weakSelf timeout] causes no harm. If you had multiple statements that all used weakSelf or relied on the state of weakSelf, then you would want to create a strong reference for the scope of all of the statements.

Ian MacDonald
  • 13,472
  • 2
  • 30
  • 51
  • However, in this particular example there's no need to do that because sending a `timeout` message to `nil` would be harmless. – jlehr Jan 20 '15 at 16:03
  • The issue isn't that `weakSelf` might be `nil` before `timeout` is called; it's that might be made `nil` *during* `timeout`'s execution. – Ian MacDonald Jan 20 '15 at 16:06
  • @IanMacDonald That's the case with `__unsafe_unretained` references but actually isn't true with `__weak` references. Calling a method on a `__weak` reference automatically retains that object for the duration of the method, so in this example the conversion to a strong reference is completely superfluous (but harmless). See: http://clang.llvm.org/docs/AutomaticReferenceCounting.html#id23 – Darren Jan 20 '15 at 17:00
  • Interesting. I didn't know there was a difference. Thanks for the link; that's a nice reference. – Ian MacDonald Jan 20 '15 at 17:04
  • "By using weakSelf in the block, you are avoiding retain cycles." There is actually no evidence that there would be a retain cycle here. – newacct Jan 20 '15 at 21:36
  • @newacct: I was speaking generally in that sentence. – Ian MacDonald Jan 20 '15 at 21:39