Using __block and __weak

20,037

Solution 1

__block is a storage qualifier. It specifies that the variable should directly be captured by the block as opposed to copying it. This is useful in case you need to modify the original variable, as in the following example

__block NSString *aString = @"Hey!"; 
void(^aBlock)() = ^{ aString = @"Hello!" }; // without __block you couldn't modify aString
NSLog(@"%@", aString); // Hey!
aBlock();
NSLog(@"%@", aString); // Hello!

In ARC this causes the variable to be automatically retained, so that it can be safely referenced within the block implementation. In the previous example, then, aString is sent a retain message when captured in the block context.

Note that this isn't true in MRC (Manual Reference Counting), where the variable is referenced without being retained.

Marking it as __weak causes the variable not to be retained, so the block directly refers to it but without retaining it. This is potentially dangerous since in case the block lives longer than the variable, since it will be referring to garbage memory (and likely to crash).

Here's the relevant paragraph from the clang doc:

In the Objective-C and Objective-C++ languages, we allow the __weak specifier for __block variables of object type. [...] This qualifier causes these variables to be kept without retain messages being sent. This knowingly leads to dangling pointers if the Block (or a copy) outlives the lifetime of this object.

Finally the claim that __block can be used to avoid strong reference cycles (aka retain cycles) is plain wrong in an ARC context. Due to the fact that in ARC __block causes the variable to be strongly referenced, it's actually more likely to cause them.

For instance in MRC this code breaks a retain cycle

__block typeof(self) blockSelf = self; //this would retain self in ARC!
[self methodThatTakesABlock:^ {
    [blockSelf doSomething];
}];

whereas to achieve the same result in ARC, you normally do

__weak typeof(self) weakSelf = self;
[self methodThatTakesABlock:^ {
    [weakSelf doSomething];
}];

Solution 2

You should use __block if you want to change variable value in block.

e.g:

__block BOOL result = NO;
dispatch_sync(dispatch_get_main_queue(), ^{
  ...
  result = YES;
  ...
});

You should use __weak if you want to avoid retain cycles.

e.g.:

__weak typeof(self) wself = self;
self.foobarCompletion = ^{
  ...
  wself.foo = YES;
  ...
};

You can combine them if there is a need.

Share:
20,037

Related videos on Youtube

Adam
Author by

Adam

Updated on July 14, 2022

Comments

  • Adam
    Adam almost 2 years

    I've read over this thread: What does the "__block" keyword mean? which discusses what __block is used for but I'm confused about one of the answers. It says __block is used to avoid retain cycles, but the comments underneath it leave me unsure.

    I'm using it something like this:

     self.someProperty = x; //where x is some object (id)
     __block __weak VP_User *this = self;
    
     //begin a callback-style block
         this.someProperty = nil;
    

    Do I need to use both __block and __weak? Any glaring problems with this way this looks?

    • trojanfoe
      trojanfoe over 10 years
      No it probably says "__weak is used to avoid retain cycles".
    • Adam
      Adam over 10 years
      Actually one of the answers (upvoted, but not accepted) says "__block is sometimes used to avoid retain cycles"
    • trojanfoe
      trojanfoe over 10 years
      I don't understand that; using __weak is the way to avoid that.
    • Adam
      Adam over 10 years
      Me neither - hence this thread asking for clarification. Is it okay to use both?
    • trojanfoe
      trojanfoe over 10 years
      I think so; they are different things and the issue with retain cycles is normally for code within the block, not outside of it.
    • Martin R
      Martin R over 10 years
      Perhaps the confusion stems from the fact that in Manual Reference Counting, the __block specifier indeed causes the object not to be retained and thus can avoid a retain cycle. This behavior is different in ARC (which is documented somewhere in the "Transitioning to ARC Release Notes").
    • Gabriele Petronella
      Gabriele Petronella over 10 years
      @MartinR exactly. In MRC, for instance, declaring a __block reference to self breaks potential retain cycles. I added an example in my answer to clarify this.
  • Adam
    Adam over 10 years
    So, if I am reading this correctly, it doesn't make sense to use __block and __weak together because they, in fact, do opposite things (in ARC)?
  • Gabriele Petronella
    Gabriele Petronella over 10 years
    No. It may make sense in case you want to modify an object within a block, but holding a reference to it would cause a retain cycle. I cannot come up with a good example, but there might exist a legitimate use. That's why it's allowed, even though potentially unsafe, as the documentation remarks.
  • Hot Licks
    Hot Licks over 10 years
    "In ARC this causes the variable to be automatically retained" How does retaining the variable work? The "variable" that needs to be kept accessible is the pointer *aString, not an object. How do you retain a pointer?
  • Gabriele Petronella
    Gabriele Petronella over 10 years
    Not sure I'm fully understanding your question. As far as I know it sends retain to aString.
  • Gabriele Petronella
    Gabriele Petronella over 10 years
    Also if a block is moved to the heap, __block variables are transparently moved as well
  • Hot Licks
    Hot Licks over 10 years
    Sending retain to aString only retains the object containing "Hey!" The pointer *aString presumably has some existence scope that needs to extend through the existence of the block and also through the existence of the calling procedure. How is that managed?
  • Gabriele Petronella
    Gabriele Petronella over 10 years
    As I said __block variables can be moved around "magically". If the block outlives the scope of the variable by being copied on the heap, every __block variable it captures is moved to the heap as well. Bottom line, the trick is that __block variables can mutate their address over time.
  • newacct
    newacct over 10 years
    @HotLicks: *aString is not a variable. aString is a variable.
  • Ferran Maylinch
    Ferran Maylinch almost 9 years
    If I'm not wrong, for a retain cycle to occur you would have to keep a direct or indirect reference to the block in self (e.g. self.block = block). So a retain cycle is not created just by using self inside the block. You don't need a weakSelf if you don't store the block.
  • Ash
    Ash over 7 years
    @Ferran That is my understanding of retain cycles involving blocks, as well.