2

I understand that __block in ARC retains the variable. This can then be used when accessing a variable within a block before the variable has been assigned, as in:

  __block __weak id observer = [[NSNotificationCenter defaultCenter] addObserverForName:MPMoviePlayerPlaybackDidFinishNotification object:player queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification* notif){
    // reference the observer here. observer also retains this block,
    // so we'd have a retain cycle unless we either nil out observer here OR
    // unless we use __weak in addition to __block. But what does the latter mean?
  }];

But I am having trouble parsing this. If __block causes the observer to be retained by the block, then what does it mean to effectively be both strong and weak? What is the __weak doing here?

Aaron
  • 619
  • 6
  • 15
  • `observer` will be uninitialized while block will be copied, so you can't reference it inside block anyway. – beefon Jan 05 '13 at 12:11
  • 2
    And `__weak` + `__block` means that variable is weak-referenced and can be changed by the code that is executed in the block. – beefon Jan 05 '13 at 12:12
  • First comment isn't quite correct, you can reference it if you know that the block won't execute before the assignment is done. (See also 8477629) – Aaron Jan 05 '13 at 12:13
  • I guess the issue is that I'm just conflating __block and __strong in my head incorrectly. Is this an accurate assessment of the code above: neither the stack frame nor the block has a strong reference to the observer. The observer is only retained and kept alive by the notification center. So although the observer retains the block, there is no retain cycle. – Aaron Jan 05 '13 at 12:29

1 Answers1

6

__block means that the variable is like global, that survives the current frame stack, and accessible by the block that you will declare in the scope.

__weak means that the variable doesn't retain the pointed object, but if the object gets deallocated the __weak pointer will be set to nil.

In your case observer catches the return value of addObserverForName:object:queue:usingBlock: , so it doesn't need to be strong. And if was strong then it was retaining the observer, making it global and surviving until the strong reference was set to nil.

Example

#import <Foundation/Foundation.h>

void (^foo()) ()
{
    NSString* str= [[NSString alloc]initWithFormat: @"Hey"];
    __block __weak NSString* x= str;
    return ^
    {
        NSLog(@"%@",x);
    };
}

int main(int argc, char** argv)
{
    @autoreleasepool
    {
        void (^block) ()= foo();
        block();
    }
    return 0;
}

This example prints (null), let's see what happened:

  • The string @"Hey" has 1 as ARC reference count;
  • It is used in the block, but since it's weak it's not retained by the block, so it still has the count to 1;
  • The block is returned and executed, since we exit from the foo function scope, the string is deallocated and the pointer x is set to nil.

So you could just do it like this:

void (^foo()) ()
{
    NSString* str= [[NSString alloc]initWithFormat: @"Hey"];
    return ^
    {
        NSLog(@"%@",str);
    };
}

There's no problem: str is strong by default so it's captured, you don't need the __block specifier.

Ramy Al Zuhouri
  • 21,580
  • 26
  • 105
  • 187
  • But per http://developer.apple.com/library/ios/#releasenotes/ObjectiveC/RN-TransitioningToARC/Introduction/Introduction.html: "In ARC mode, __block id x; defaults to retaining x (just like all other values)" – Aaron Jan 05 '13 at 12:36
  • I guess that just means it is retained as usual by the stack frame, NOT that it is retained by the block? – Aaron Jan 05 '13 at 12:36
  • It defaults to retaining x, but with a __weak specifier it doesn't. – Ramy Al Zuhouri Jan 05 '13 at 12:38
  • "In manual reference counting mode, __block id x; has the effect of not retaining x. In ARC mode, __block id x; defaults to retaining x (just like all other values). To get the manual reference counting mode behavior under ARC, you could use __unsafe_unretained __block id x;." – Ramy Al Zuhouri Jan 05 '13 at 12:38
  • I guess this answers the question: "It defaults to retaining x, but with a __weak specifier it doesn't." It's just really confusing to have to keep in mind that __block now means retained under ARC, except when __weak is present, and then that takes precedence. In my mind, it reads like "__strong __weak". – Aaron Jan 05 '13 at 12:47
  • Is it fair to say that, rather than being a synonym for __strong under ARC, __block instead simply has no effect on strong or weak anymore the way it used to in manual reference counting? – Aaron Jan 05 '13 at 12:49
  • Hard to explain, see the example :-) – Ramy Al Zuhouri Jan 05 '13 at 13:00