9

Consider this:

id observer = [[NSNotificationCenter defaultCenter] 
    addObserverForName:MyNotification 
                object:nil 
                 queue:nil 
            usingBlock:^(NSNotification *note) {
                [[NSNotificationCenter defaultCenter] 
                        removeObserver:observer 
                                  name:MyNotification 
                                object:nil
            ];
            // do other stuff here...
    }
];

I'm using this pattern to observe a notification once and then stop observing it. But LLVM tells me (under ARC) that Variable 'observer' is uninitialized when captured by block.

How can I fix this, since the block necessarily captures the variable before initialization, it being part of the initializer? Will using the __block qualifier on observer do the trick?

jscs
  • 63,694
  • 13
  • 151
  • 195
Steveo
  • 2,238
  • 1
  • 21
  • 34
  • possible duplicate of [Why doesn't Remove Observer from NSNotificationCenter:addObserverForName:usingBlock get called](http://stackoverflow.com/questions/8477629/why-doesnt-remove-observer-from-nsnotificationcenteraddobserverfornameusingbl) – jscs Oct 22 '13 at 21:01

3 Answers3

18

As explained in the answers to

Why doesn't Remove Observer from NSNotificationCenter:addObserverForName:usingBlock get called,

you have to

  • add __block, so that the block will refer to the initialized variable, AND
  • add __weak, to avoid a retain cycle. (The latter applies only to ARC. Without ARC, the block does not create a strong reference to a __block variable.)

Therefore:

__block __weak id observer = [[NSNotificationCenter defaultCenter] ...
Community
  • 1
  • 1
Martin R
  • 529,903
  • 94
  • 1,240
  • 1,382
  • because the app targets 10.6, I must use __unsafe_unretained in lieu of __weak. In spite of the name, can it be assured that observer won't dealloc before the block runs? – Steveo Oct 22 '13 at 21:01
  • @Steveo: I have silently assumed that Automatic Reference Counting is used. Without ARC, `__block` should be sufficient, because then the block does not capture a strong reference to a `__block` variable. I will update the answer accordingly. – Martin R Oct 22 '13 at 21:04
  • @Steveo: Now I see what you mean. You use ARC, but cannot use __weak. I think __unsafe_unretained should work as expected. – Martin R Oct 22 '13 at 21:11
  • @newacct: Without __weak, `observer` is not deallocated after the notfication has been posted and the block was executed, and Instruments reports a cycle. – Martin R Oct 24 '13 at 09:07
0

yes, I think declaring observer beforehand as __block id observer; should work.

Brad Allred
  • 7,323
  • 1
  • 30
  • 49
0

Yes, using __block will solve the problem.

Without it, the Block gets a copy of the variable's value at the time the Block is created. (Which is "uninitialized" in this case.) With it, the Block (in essence) gets the variable itself, so that the value can be changed from within the Block. Thus it will also "track" changes made from outside.

jscs
  • 63,694
  • 13
  • 151
  • 195