self
is merely a captured variable inside a block and doesn't reference the block itself, so how does a block reference itself without having an explicit captured variable for that purpose?

- 4,599
- 4
- 23
- 30
5 Answers
__block void(^strawberryFields)();
strawberryFields = [^{ strawberryFields(); } copy];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0),
strawberryFields);
you use the
__block
because the block will make a copy of the value ofstrawberryFields
when the block is created which will be before the assignment.you also must
copy
the block prior to any other copy operation or else you'll end up with a block that references the on-stack original version.note that the above code leaks the block. Somewhere, there needs to be a
release
of that block to balance the copy.

- 162,346
- 23
- 271
- 359
-
1"Somewhere, there needs to be a release" why not right after the `dispatch_async`? – user102008 Jun 07 '12 at 03:21
-
I think "Somewhere, there needs to be a release" means that strawberryFields needs to be set to nil at some point. Otherwise, it's "Strawberry fields forever..." – Andrew Rondeau Aug 16 '16 at 01:55
-
@AndrewRondeau This was written before ARC was really a thing. :) – bbum Aug 17 '16 at 16:33
I found this pattern to work and stable for ARC (automatic reference counting), both in Debug and Release builds.
-(void) someMethod
{
// declare a __block variable to use inside the block itself for its recursive phase.
void __block (^myBlock_recurse)();
// define the block
void (^myBlock)() = ^{
// ... do stuff ...
myBlock_recurse(); // looks like calling another block, but not really.
};
// kickstart the block
myBlock_recurse = myBlock; // initialize the alias
myBlock(); // starts the block
}
Initially I tried just putting a __block
modifier to myBlock
and use that variable directly to recurse within the block's implementation. That works on the ARC Debug build but breaks with an EXC_BAD_ACCESS
on the Release build. On the other hand removing the __block
modifier raises a "variable not defined when captured by block" warning (and I was reluctant to run it and test).

- 8,285
- 6
- 52
- 91
-
-
can you show an example of code that crashes when you just use `myBlock` but does not crash when you use this `myBlock_recurse` thing? – user102008 Jun 07 '12 at 08:22
-
3
-
@newacct Temporary retain cycle – just make sure you assign `nil` to `myBlock_recurse` after recursion is done. – adib Dec 11 '17 at 09:26
The block needs some way to nil out its own reference. Typically it is done by storing the block in a property of the class.
Sometimes you can prefer to not use a property. Here is how you do it without a property:
__weak id weakSelf = self;
__block id block = ^{
if(weakSelf) {
// .. do whatever
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 5 * NSEC_PER_SEC), dispatch_get_main_queue(), block);
}
else {
block = nil;
}
};
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 5 * NSEC_PER_SEC), dispatch_get_main_queue(), block);
The key thing to keep in mind is that all code paths must lead to a block = nil. We do that here by calling the block every 5 seconds until weakSelf turns nil.

- 1,030
- 11
- 15
-
As of XCode 5.0 (currently in beta) this throws a warning. The warning is wrong -- hopefully Apple makes this warning smarter in the future. – Dustin Jun 19 '13 at 23:33
-
It's not wrong. You *are* causing a retain cycle (even if you try to break it later, which I'm not sure is correct). The better solution is to not have a retain cycle in the first place, by having the block capture a weak reference to itself. – newacct Jun 21 '13 at 18:36
-
If you're skeptical I suggest testing the code in XCode. Setting block = nil removes the retaining reference in arc. You can test it be setting a breakpoint at block = nil and copying the pointer to block in the pasteboard. Let the program run for a while (seems to take 1-5 seconds), pause the program, and po the pointer. In this way you can easily tell the object is destroyed. – Dustin Aug 11 '13 at 22:09
Note that in ARC, it's a little different -- __block
object pointer variables are by default retained in ARC, unlike in MRC. Thus, it will cause a retain cycle. It is necessary for the block to capture a weak reference to itself (using __weak
) in order to not have a retain cycle.
However, we still need a strong reference to the block somewhere. If there are no strong references, the block (which is on the heap since it's copied) will be deallocated. Thus, we need two variables, one strong and one weak, and inside the block use the weak one to reference itself:
__block __weak void(^weakBlock)();
void(^myBlock)();
weakBlock = myBlock = [^{ weakBlock(); } copy];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0),
myBlock);

- 119,665
- 29
- 163
- 224
-
-
@trss: Some versions of the compiler might automatically insert a copy (so you might not see any difference), but this is not guaranteed. If a copy is not made, the problem is that `weakBlock` will point to the stack block. And even though we might later be using a copy of the block (heap block), inside the block, the code still refers to `weakBlock`, which points to the stack block, so it will execute the stack block and cause problems. That's why the block must be copied before assigning to `weakBlock`. – newacct Jul 07 '13 at 05:30
-
This doesn't work. It gives a warning about assigning to a weak variable (weakBlock), and the warning is right: weakBlock is deallocated immediately. – puzzl Nov 04 '14 at 20:58
-
@puzzl: The warning is not right. It is assigned to `myBlock` which is a strong reference. An assignment expression evaluates to the result of the right side, and that result is assigned to a strong reference. The compiler is incorrectly picky about the ordering of the assignment. The code is correct according to the standard, but I have changed it to get rid of the warning. – newacct Nov 04 '14 at 21:43
I have never tried this before and not 100% sure it's useful, if valid, but for example:
typedef void (^BasicBlock)(void);
__block BasicBlock testBlock;
testBlock = ^{NSLog(@"Testing %p", &testBlock);};
testBlock();
You probably have declare the variable with __block to prevent self-retain cycle.

- 6,405
- 2
- 25
- 26
-
Code is decidedly odd, but more or less correct. The reasoning, though, is incorrect. – bbum Mar 05 '11 at 04:14
-
Sure; see my answer. The code wasn't that odd, really, just that printing the address of an `__block` variable is typically surprising (in that there is an implied indirection). – bbum Mar 05 '11 at 04:19
-
Yes, the address means nothing indeed. And I wasn't aware that the block will make a copy of the value _before_ the assignment, so __block is necessary regardless of self retaining. Thank you for the comment. If you let me ask just one more thing, how does block actually deal with __block variable when writing to it? Does it make a reference to the original (and possibly in-stack) variable? – MHC Mar 05 '11 at 04:26
-
A `__block` variable is effectively a handle; a pointer to where the data is actually held. It starts on the stack. When you do a Block_copy() (or -copy), it allocates a bit of memory on the heap to hold the variables value, copies it, then updates the pointer in the __block to no longer point to the stack. – bbum Mar 05 '11 at 05:10
-
Thanks a lot. Then if I copy a block, in which I change the value of a __block variable, then the change is not visible inside the original scope? – MHC Mar 05 '11 at 05:18