Capturing a variable in a Block when the Block is

2020-03-02 04:51发布

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?

3条回答
姐就是有狂的资本
2楼-- · 2020-03-02 05:16

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.

查看更多
够拽才男人
3楼-- · 2020-03-02 05:23

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] ...
查看更多
Fickle 薄情
4楼-- · 2020-03-02 05:32

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

查看更多
登录 后发表回答