Consider the following code fragment:
for(/* some condition */) {
int x = rand();
[array addObject:^(){
NSLog(#"%d", x);
}]
}
for(void (^block)() in array) {
block();
}
Now I would expect this code snippet to print out all values assigned to x in that for loop; however it seems that all blocks share the same 'x' variable (presumably the last one).
Any idea why this is so and how I could fix the code to have each block contain the variable 'x' as it was at the time the block was defined?
The documentation specifically says not to do this. The reason is that blocks are allocated on the stack, which means they can go out of scope. For the same reason you can't access the variable x outside of the first for loop, you also shouldn't use that block. x has gone out of scope, along with the block itself, and could contain any value.
To get around this, you can take a copy of the block like so:
for(/* some condition */) {
int x = rand();
void(^logBlock)() = ^() { NSLog(#"%d", x); }
[array addObject:[[logBlock copy] autorelease]];
}
This moves the block onto the heap, and should fix your problem.
Related
What are the semantics of capturing a variable by a block in objective-C?
#import <Foundation/Foundation.h>
#include <stdio.h>
int main()
{
NSMutableArray *arr = [NSMutableArray array];
for (int i = 0; i < 100; ++i) {
int j = i;
[arr addObject:^(void) {printf("%d %d\n", i, j); }];
}
for (void (^blk)(void) in arr) {
blk();
}
}
I was expecing this to print something like:
100 0
100 1
...
100 99
Instead, it prints:
99 99
99 99
...
99 99
How is it even possible that it's interpreting j as equal to 99 ? j isn't even alive outside the for loop.
Because you're not using ARC! Without it, your block isn't being copied. You're just getting lucky and running the very last block every single time.
The reason you're seeing 99 99 many times is simply due to undefined behaviour.
Let's take the first for-loop:
for (int i = 0; i < 100; ++i) {
int j = i;
dispatch_block_t block = ^(void) {printf("%d %d\n", i, j); };
[arr addObject:block];
}
[I've pulled out the block for clarity.]
Inside this for-loop, the block is created. It is created on the stack and never moved to the heap because there is no copy of the block to do so.
Each time around the for-loop, it's extremely likely (well, certain really) that the same stack space is used for the block. And then the address of the block (which is on the stack) is added to arr. The same address each time. But it's a new implementation of the block each time.
Once out of the first for-loop, arr contains the same value 100 times. And that value points to the last created block, which is still on the stack. But it's pointing to a block on the stack that can no longer be accessed safely because it's out of scope.
In the case of this example however, the stack space occupied by the block by sheer luck (OK, simple code) hasn't been reused. So when you go and use the block, it "works".
The correct solution is to copy the block when it is added to the array. Either by calling copy or letting ARC do that for you. That way, the block is copied to the heap and you have a reference counted block that will live as long as needed by the array and the scope in which it is created.
If you want to learn more about how blocks work and understand this answer more deeply, then I suggest my explanations here:
http://www.galloway.me.uk/2012/10/a-look-inside-blocks-episode-1/
http://www.galloway.me.uk/2012/10/a-look-inside-blocks-episode-2/
http://www.galloway.me.uk/2013/05/a-look-inside-blocks-episode-3-block-copy/
This question already has an answer here:
Blocks and stack
(1 answer)
Closed 8 years ago.
Please take a look at this piece of code:
NSMutableArray *array = [NSMutableArray array];
for (int i = 0; i < 10; i++)
{
void (^b)() = ^{printf("%d\n", i);};
[array addObject:b];
}
for (id obj in array)
{
void(^b)() = obj;
b();
}
[array removeAllObjects];
I expected this code to output 0, 1, 2 and so on but it prints 9 always. But why? Doesn't it capture i on every loop iteration? Why the last value is always captured? But what is more confusing for me is that if i change this line:
void (^b)() = ^{printf("%d\n", i);};
to
void (^b)() = [^{printf("%d\n", i);} copy];
then it starts printing 0, 1, 2 and so on. Can anybody please explain why it works this way?
This is not a problem with what the block captures, but rather with what block gets stored in the array. If you print addresses of the blocks after the first loop, you should see identical addresses being printed:
for (id obj in array)
{
printf("%p\n", (void*)obj);
}
This is because all ten blocks are created on the stack in a loop, and are placed at the same address. Once the loop is over, the block created inside it is out of scope. Referencing it is undefined behavior. However, now that you stored the address of the block, you have a way to reference it (illegally).
Since the last block that was created in your loop has captured the last value of i (which is nine) all invocations of your block from your second loop would invoke the same block that prints nine.
This behavior changes if you copy the block, because now it is completely legal to reference it outside the scope where it has been created. Now all your blocks have different addresses, and so each one prints its own different number.
I know that a block descriptor is passed on the stack to a block function when it is invoked. Is there a variable name I can use to refer to this in my code (like self or _cmd for methods)
(^{
// how can I access the block descriptor here?
})();
edit
I actually want the block object, not the block descriptor...
In short, you can't. At least not directly (there is nothing akin to self within a block -- we thought long and hard about that, but couldn't come up with something both elegant nor enough need for it in light of the following pattern to justify adding such syntax).
If you want to refer to the block, you need to do something like:
__block void(^strawberryFields)();
strawberryFields = ^{ strawberryFields(); };
strawberryFields();
Note that the above will run forever. Note also that you might want to copy that block upon assignment if you plan on using the block later.
Consider:
NSMutableArray *array = [NSMutableArray array];
int i;
for(i = 0; i<5; i++) {
[array addObject:[^{ return i*i; } copy]];
}
You'll end up with an array with 5 blocks, each capturing a different value of i.
It may help to create a method to initialize each block for you. Here's a quick test that demonstrates each block has its own variable:
-(void (^)(void))intAddingBlock:(NSString *)name {
__block int intForThisBlock = 0;
return ^{
NSLog(#"%# before: %d", name, intForThisBlock);
intForThisBlock += 5;
NSLog(#"%# after: %d", name, intForThisBlock);
};
}
-(void)testTheBlock {
void(^block1)(void) = [self intAddingBlock:#"block 1"];
void(^block2)(void) = [self intAddingBlock:#"block 2"];
block1();
block1();
block2();
block1();
block2();
}
Output:
block 1 before: 0
block 1 after: 5
block 1 before: 5
block 1 after: 10
block 2 before: 0
block 2 after: 5
block 1 before: 10
block 1 after: 15
block 2 before: 5
block 2 after: 10
Is it possible to implement something like a Smalltalk-style whileTrue: method in Objective-C using blocks? Specifically, instead of:
int count = 0;
while (count < 10)
{
NSLog(count);
count++;
}
I'd like to be able to do (via a wrapper on the bool primitive called OOBoolean) something like...
__block int count = 0;
[[OOBoolean booleanWithBool: count < 10] whileTrueDo: ^() {
NSLog(count);
count++;
}];
I'm having trouble understanding how this would be implemented though...
Here you have a couple of ideas,
Assuming your bool wrapper implements boolValue, a naive implementation could be:
-(void) whileTrueDo:(void (^)(void)) block{
while ([self boolValue]) {
block();
}
}
In order for the wrapper to change its bool value after each iteration, the block must be able to actually change the variable that is used to calculate the boolean condition. So, in your case, by setting the __block type modifier to count, and increasing count in each block execution, you should be able to make it work.
The problem is, if you create your wrapper by sending the evaluated condition, as you stated in your question, you wont be able to change its bool value in each iteration. So, I would change the way the wrapper is created and the whileTrueDo: naive implementation so the boolean wrapper uses an evaluation block.
__block int count = 0;
OOBooleanBlock evaluationBlock = ^BOOL{
return count < 10;
};
[[OOBoolean booleanWithBlock:evaluationBlock] whileTrueDo: ^() {
NSLog(count);
count++;
}];
//In OOBoolean
+(OOBoolean*) booleanWithBlock:(OOBooleanBlock) evaluationBlock{
//Instantiate, set the evaluationBlock ivar and return the ooboolean object.
}
-(void) whileTrueDo:(void (^)(void)) block{
while (self.evaluationBlock()) {
block();
}
}
Remember to use the __block type modifier, otherwise you will enter in an infinite loop.
I haven't tested this, I hope this helps you though.
Cheers
I've started using blocks, and one of the first things I encountered is an inability to set values which are captured by the closure. This is fine, I've been using C/C++ a long time. I'll just use pointers!
MyObject* bestObj = nil;
float bestDist= 10000.f;
MyObject **pBestObj = &bestObj;
float* pBestDist = &bestDist;
[self testObjects:class block:^(MyObject* obj){
CGRect r = [obj boundingBox];
// position is captured from outside this code sample
if( CGRectContainsPoint( r, position ) )
{
float dist = GetDistance( obj, position );
if(dist < bestDist)
{
*pBestDist = dist;
*pBestObj = obj;
}
}
}];
return bestObj;
My question is, is this safe? I assume that as long as my pointer points to something that hasn't gone out of scope and that still exists, that it should work. But I'm also assuming that things that take blocks don't ever, say, run them in parallel. I know my code doesn't, but I don't know about, say, using a block with an NSArray enumerateObjectsUsingBlock call.
The 'right' way to do this would be to mark those original variables as block mutable, __block