Why did Apple design __block for write auto var in block? - objective-c

We can read auto var in block:
int aVar = 1;
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
NSLog(#"theVar==%d", aVar);
});
But can not write:
int aVar = 1;
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
aVar = 2;
NSLog(#"theVar==%d", aVar);
});
Xcode showed:Variable is not assignable (missing __block type specifier).
I know that when there is no __block,auto var pass to block as a copy so it's readonly.And with __block its address pass to block.
But I can't understand why Apple must design as this?Just copy address to block is not OK?Is there any potential problem If auto var in block without __block is writeable?

It's not as simple as "with __block its address pass to block", because a block that captures the variable can outlive the scope that it's created in, and a local variable of automatic storage duration would become invalid at the end of the scope, so just capturing its address won't work.
A variable declared with __block actually involves a hidden structure behind the scenes, which can be "moved" from the stack to the heap if necessary so it can outlive the scope it was created in, and there are additional hidden fields that the compiler generates behind the scenes to allow someone accessing the variable to figure out the real location of the variable (stack or heap) at that time. Also, the blocks need to manage the memory of the copy of the variable on the heap. So defining a __block variable requires additional storage compared to the variable itself, and accessing a __block variable requires more levels of indirection and more memory management logic for the blocks involved. This additional complication should only be used if needed; therefore, variables captured by blocks are not __block by default.

Related

Can two local variable blocks call each other? Scope issue due to order of declaration

I have two blocks declared as local variables. A networking block that calls a retry block on error, and a retry block that calls the networking block.
The retry block is called in several different error circumstances, hence using a block to eliminate duplicated code.
However, this scenario does not work due to the source code order of the declared blocks.
void (^upperBlock)() = ^{
// variable is used before it is declared.
lowerBlock(); // Error: implicit declaration of function `lowerBlock` is invalid in C99
};
void (^lowerBlock)() = ^{
upperBlock(); // ok!
};
It does not work to give the lower block a forward declaration, as the upper block captures the initial value of the forward declaration before the variable is reassigned (even if it is called later).
void (^lowerBlock)() = nil;
void (^upperBlock)() = ^{
lowerBlock(); // crash! block is `nil`
};
lowerBlock = ^{
// new value not assigned, despite `upperBlock` being *called* below this point
};
upperBlock()
I could use __block on the lowerBlock, in which case the upperBlock will call the freshly assigned version of the variable. But using __block seems like overkill for this scenario if another solution is possible.
Is there any inline, block-as-a-local-variable solution to allow the upper and lower blocks to reference each other?
Captures are by value with Blocks unless the variable is marked as __block. That's the correct solution here.
If you declare lower as a __block variable, it will be captured as a reference rather than taken as a copy, and the upper will see its "current" value when called:
__block BOOL proceedWithInfiniteRegress = YES;
__block dispatch_block_t lower;
dispatch_block_t upper = ^{
if( proceedWithInfiniteRegress ){
lower();
}
};
lower = ^{
proceedWithInfiniteRegress = NO;
NSLog(#"Hello, reference cycle!");
upper();
};
upper();

Why does ARC only sometimes retain a __block out pointer?

1) Why does this retain its __block var:
{
void (^blockWithOutPointer)(NSObject * __autoreleasing *) = ^(NSObject * __autoreleasing * outPointer) {
*outPointer = [NSObject new];
};
NSObject * __block blockVar1;
dispatch_after(dispatch_time(DISPATCH_TIME_NOW,
(int64_t)(1 * NSEC_PER_SEC)),
dispatch_get_main_queue(),
^{
NSLog(#"blockVar1: %#",
blockVar1);
// prints non-nil. WHY????
});
blockWithOutPointer(&blockVar1);
}
2) But this doesn't?
void (^blockWithOutPointerThatDispatchesLater)(NSObject * __autoreleasing *,
dispatch_block_t) = ^(NSObject * __autoreleasing * outPointer,
dispatch_block_t block) {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW,
(int64_t)(1 * NSEC_PER_SEC)),
dispatch_get_main_queue(),
block);
*outPointer = [NSObject new];
};
{
NSObject * __block blockVar2;
blockWithOutPointerThatDispatchesLater(&blockVar2,
^{
NSLog(#"blockVar2: %#",
blockVar2);
});
// prints nil, which is expected.
}
3) If I instead use an __autoreleasing variable as my out pointer destination, and then assign that variable to my __block pointer, everything works fine.
{
NSObject * __autoreleasing autoreleasingVar;
NSObject * __block blockVar3;
blockWithOutPointerThatDispatchesLater(&autoreleasingVar,
^{
NSLog(#"blockVar3: %#",
blockVar3);
});
blockVar3 = autoreleasingVar;
// prints non-nil, which is expected.
}
I've read CRD's answer about ARC pointer-to-pointer issues, it makes sense that #2 would print nil because ARC assumes that blockVar2 is __autoreleasing, and doesn't retain its value. Thus, in #3, when we assign autoreleasingVar to blockVar3, ARC properly retains the value. However, there is no such assignment for #1. Why does #1 retain its value?
Even more amazingly, #1 is unaffected if I wrap the out-pointer assignment in an #autoreleasepool:
{
void (^blockWithOutPointer)(NSObject * __autoreleasing *) = ^(NSObject * __autoreleasing * outPointer) {
#autoreleasepool {
*outPointer = [NSObject new];
}
};
NSObject * __block blockVar1;
dispatch_after(dispatch_time(DISPATCH_TIME_NOW,
(int64_t)(1 * NSEC_PER_SEC)),
dispatch_get_main_queue(),
^{
NSLog(#"blockVar1: %#",
blockVar1);
// still prints non-nil. WHY???
});
blockWithOutPointer(&blockVar1);
}
Whereas #3 crashes, as expected since the #autoreleasepool released the out-pointer's object, and I guess ARC doesn't set __autoreleasing variables to nil.
void (^blockWithOutPointerThatDispatchesLater)(NSObject * __autoreleasing *,
dispatch_block_t) = ^(NSObject * __autoreleasing * outPointer,
dispatch_block_t block) {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW,
(int64_t)(1 * NSEC_PER_SEC)),
dispatch_get_main_queue(),
block);
#autoreleasepool {
*outPointer = [NSObject new];
}
};
{
NSObject * __autoreleasing autoreleasingVar;
NSObject * __block blockVar3;
blockWithOutPointerThatDispatchesLater(&autoreleasingVar,
^{
NSLog(#"blockVar3: %#",
blockVar3);
// crashes on the NSLog!
});
blockVar3 = autoreleasingVar;
}
I filed a radar about this.
You have discovered a "feature" of the block implementation and (at least for cases 1 & 2, I haven't checked further) it is nothing to do with __autoreleasing per se.
First let's look at your case 1. You seem surprised this prints a non-nil value. It works exactly as expected:
blockWithOutPointer(&blockVar1); executes, assigning a value to blockVar1; then
the block ^{ NSLog(#"blockVar1: %#", blockVar1); } is executed by GCD and the stored by (1) is printed.
(Note: You can removed the __autoreleasing qualifiers and it will work the same as this is the inferred mode for pass-by-writeback parameters.)
Now your case 2. This is where you hit the "feature":
In Objective-C objects are heap allocated; and
Objective-C blocks are objects; so
Ergo blocks are heap allocated...
Except when they are not...
As an optimisation the block specification allows blocks and their captured __block variables to be stack allocated and only moved onto the heap when their lifetime needs to be longer than the stack frame are in.
As an optimisation it should (a) be essentially invisible to the programmer - apart from any perf benefit and (b) not change the semantics in anyway. However Apple decided to initially introduce it as a "programmer assisted optimisation" and have then slowly improved matters.
The behaviour of your case 2 is all down to when the block and __block variable get copied onto the heap. Let's look at the code:
NSObject * __block blockVar2;
This declares blockVar2 to have __block storage duration, which allows a block to alter the value of this locally declared variable. At this point the compiler does not know whether a block may access it, in which case blockVar2 will need to be on the heap, or whether it won't, in which case it may be on the stack.
The compiler decides it prefers the stack and allocates blockVar2 there.
blockWithOutPointerThatDispatchesLater(&blockVar2,
Now the compiler needs to pass the address of blockVar2 as the first argument, the variable is currently on the stack, and the compiler emits code to calculate its address. That address is on the stack.
^{
NSLog(#"blockVar2: %#",
blockVar2);
});
Now the compiler gets to the second argument. It sees the block, that the block accesses blockVar2, and that blockVar2 is qualified by __block so it must capture the variable itself and not the variables value.
The compiler decides the block should go on the heap. For this to work it needs to migrate blockVar2 onto the heap, so it does that along with its current value nil...
Oops!
The first argument is the address of the original blockVar2 on the stack, while the second argument is a block which in turn references the cloned blockVar2 on the heap.
When the code is executed blockWithOutPointerThatDispatchesLater() allocates an object and stores its address in the stack blockVar2; then GCD executes the delayed block which prints of the value of the heap blockVar2, which is nil.
A “Fix”
Just change your code to:
NSObject * __block blockVar2;
dispatch_block_t afterBlock = ^{
NSLog(#"blockVar2: %#", blockVar2);
};
blockWithOutPointerThatDispatchesLater(&blockVar2, afterBlock);
i.e. pre-calculate the second argument expression. Now the compiler sees the block before it sees &blockVar2, moves the block and blockVar2 to the heap, and the value generated for &blockVar2 is the address of the heap version of blockVar2.
Expanded Conclusion: Bug or Feature?
The original answer simply stated this is clearly a bug, not a feature, and suggest you file a bug report, noting it's been reported before but another report won't harm.
However that might be a little unfair, yes it is a bug, the question is what the bug actually is. Consider:
In (Objective-)C variables, allocated on the stack or statically, and allocated dynamic memory blocks do not move during their lifetime.
Compiler optimisations in general should not alter the meaning or correctness of a program.
Apple has implemented a compiler optimisation – storing blocks and captured __block variables on the stack – in a way which can move __block attributed variables during their lifetime and in doing so the meaning and correctness of a program can be altered.
The result is a simple re-ordering of program statements in a way which should not alter program meaning or correctness in fact does. This is bad!
Given the history of the optimisation, as implemented by Apple, which by-design relied on programmer assistance (though it has since been made more automatic) for its correctness this could simply be seen as another “feature” of the chosen implementation.
Recommendation
Never, ever, apply the address-of (&) operator to a variable with __block storage duration. If may work if you do, but it just as easily may not.
If you need to use a __block variable as a pass-by-writeback argument then copy it to a local temporary first, make the call, and finally copy it back again.
HTH
There's probably a misconception in 1):
If a variable will be imported into a block, which is marked with __block the compiler generates a helper struct containing various fields and the variable corresponding to the given source. That is, there's no pointer blockVar1, instead there's a whole struct instead.
If a block imports this variable and needs to be copied (for example, when asynchronously submitted) it also "moves" this helper struct onto the heap before "moving" the block itself onto the heap.
This statement
NSObject * __block blockVar1;
will initialise the helper struct which embeds the actual variable and initialises it to nil. The corresponding address of the variable points into the stack.
When the compiler parses this statement:
dispatch_after(dispatch_time(DISPATCH_TIME_NOW,
(int64_t)(1 * NSEC_PER_SEC)),
dispatch_get_main_queue(),
^{
NSLog(#"blockVar1: %#",
blockVar1);
// prints non-nil. WHY????
});
The compiler generates code for the compound statement, specifically it creates a struct representing the block which initially exists on the stack, too. Since this block requires to be moved to the heap before executing dispatch_async, it also moves the helper struct onto the heap in subsequently generated code.
Additionally, since the imported variable is a NSObject pointer, it also assigns function pointers (located in the helper struct) which "keep" and "dispose" the object, which will be called when the helper struct is "moved" to the heap, respectively when it is destroyed.
When you finally execute this statement
blockWithOutPointer(&blockVar1);
the address of the variable has already been changed: the variable is now located on the heap (since the helper struct has been "moved" to the heap") and exists as long as the block.
Now, to the point where you declare (and define) the following block:
void (^blockWithOutPointer)(NSObject * __autoreleasing *)
What causes gripes here is the __autoreleasing modifier, specifically Storage duration of __autoreleasing objects:
That is, __autoreleasing can only be applied to variables with automatic storage duration.
Edit:
This would assume that the given variable is on the stack. However, it is located on the heap. Thus, your program is illformed and the behaviour is undefined.
Regarding the __autoreleasing storage qualifier, the code sample 1) is correct (the _autoreleasing storage qualifier refers to a temporary that is created when passing the variable as a parameter, see comments below).
What I've said previously above should be correct, and what the user is experiencing is thus expected.
For further reference see: http://clang.llvm.org/docs/Block-ABI-Apple.html
However:
There's still a subtle potential issue with a "data race": the statement
blockWithOutPointer(&blockVar1);
will modify a pointer variable which is located on the heap, while executing on the current thread. Later, on the main thread the same variable will be read. Unless current thread equals main thread, this exhibits a classic data race.
While this is not the question and no a complete answer - it shows, how quickly such code becomes more complex than desired and I would recommend to strive for simpler, comprehensible code.
End Edit
I haven't analysed the other code samples
- but at the first glance it seems, using __autoreleasing leads also to an illformed program.

Objective-C: What's the difference between id and an opaque pointer id?

To an id-variable, I can assign a block and call it afterwards; with an opaque pointer id this doesn't work (EXC_BAD_ACCESS).
In RestKit, the userData-object is an "opaque pointer"; now, I'd like to assign a block variable to it to call this block after the request finished. But because of this EXC_BAD_ACCESS it doesn't work. Is there a chance to user this opaque pointer to assign a block to it?
Thanks a lot!
EDIT:
// this works
id testId = ^{
NSLog(#"hello");
};
testId();
// this doesn't - but it's important to know RestKit
void (^postNotification)(void) = objectLoader.userData // EXC_BAD_ACCESS
postNotification();
objectLoader is of type RKObjectLoader (subclass of RKRequest), and the API says about userData: An opaque pointer to associate user defined data with the request.
You need to show us how you're creating the block and assigning it to userData to be sure, but my guess is you're not copying the block and it's going out of scope, like this:
objectLoader.userData = ^{ ... };
A blocks are created on the stack. That means when the compound statement (e.g. function) enclosing it ends, the block is no longer valid. If you want the block to survive, you need to copy it to the heap:
objectLoader.userData = [^{ ... } copy];

What does the "__block" keyword mean?

What exactly does the __block keyword in Objective-C mean? I know it allows you to modify variables within blocks, but I'd like to know...
What exactly does it tell the compiler?
Does it do anything else?
If that's all it does then why is it needed in the first place?
Is it in the docs anywhere? (I can't find it).
It tells the compiler that any variable marked by it must be treated in a special way when it is used inside a block. Normally, variables and their contents that are also used in blocks are copied, thus any modification done to these variables don't show outside the block. When they are marked with __block, the modifications done inside the block are also visible outside of it.
For an example and more info, see The __block Storage Type in Apple's Blocks Programming Topics.
The important example is this one:
extern NSInteger CounterGlobal;
static NSInteger CounterStatic;
{
NSInteger localCounter = 42;
__block char localCharacter;
void (^aBlock)(void) = ^(void) {
++CounterGlobal;
++CounterStatic;
CounterGlobal = localCounter; // localCounter fixed at block creation
localCharacter = 'a'; // sets localCharacter in enclosing scope
};
++localCounter; // unseen by the block
localCharacter = 'b';
aBlock(); // execute the block
// localCharacter now 'a'
}
In this example, both localCounter and localCharacter are modified before the block is called. However, inside the block, only the modification to localCharacter would be visible, thanks to the __block keyword. Conversely, the block can modify localCharacter and this modification is visible outside of the block.
#bbum covers blocks in depth in a blog post and touches on the __block storage type.
__block is a distinct storage type
Just like static, auto, and volatile, __block is a storage type. It
tells the compiler that the variable’s storage is to be managed
differently....
However, for __block variables, the block does not retain. It is up to you to retain and release, as needed.
...
As for use cases you will find __block is sometimes used to avoid retain cycles since it does not retain the argument. A common example is using self.
//Now using myself inside a block will not
//retain the value therefore breaking a
//possible retain cycle.
__block id myself = self;
When you don't use __block, the block copies the variable (call-by-value), so even if you modify the variable elsewhere, the block doesn't see the changes.
__block makes the blocks keep a reference to the variable (call-by-reference).
NSString* str = #"hello";
void (^theBlock)() = ^void() {
NSLog(#"%#", str);
};
str = #"how are you";
theBlock(); //prints #"hello"
In these 2 cases you need __block:
If you want to modify the variable inside the block and expect it to be visible outside:
__block NSString* str = #"hello";
void (^theBlock)() = ^void() {
str = #"how are you";
};
theBlock();
NSLog(#"%#", str); //prints "how are you"
If you want to modify the variable after you have declared the block and you expect the block to see the change:
__block NSString* str = #"hello";
void (^theBlock)() = ^void() {
NSLog(#"%#", str);
};
str = #"how are you";
theBlock(); //prints "how are you"
__block is a storage qualifier that can be used in two ways:
Marks that a variable lives in a storage that is shared between the lexical scope of the original variable and any blocks declared within that scope. And clang will generate a struct to represent this variable, and use this struct by reference(not by value).
In MRC, __block can be used to avoid retain object variables a block captures. Careful that this doesn't work for ARC. In ARC, you should use __weak instead.
You can refer to apple doc for detailed information.
__block is a storage type that is use to make in scope variables mutable, more frankly if you declare a variable with this specifier, its reference will be passed to blocks not a read-only copy for more details see Blocks Programming in iOS
hope this will help you
let suppose we have a code like:
{
int stackVariable = 1;
blockName = ^()
{
stackVariable++;
}
}
it will give an error like "variable is not assignable" because the stack variable inside the block are by default immutable.
adding __block(storage modifier) ahead of it declaration make it mutable inside the block i.e __block int stackVariable=1;
From the Block Language Spec:
In addition to the new Block type we also introduce a new storage qualifier, __block, for local variables. [testme: a __block declaration within a block literal] The __block storage qualifier is mutually exclusive to the existing local storage qualifiers auto, register, and static.[testme] Variables qualified by __block act as if they were in allocated storage and this storage is automatically recovered after last use of said variable. An implementation may choose an optimization where the storage is initially automatic and only "moved" to allocated (heap) storage upon a Block_copy of a referencing Block. Such variables may be mutated as normal variables are.
In the case where a __block variable is a Block one must assume that the __block variable resides in allocated storage and as such is assumed to reference a Block that is also in allocated storage (that it is the result of a Block_copy operation). Despite this there is no provision to do a Block_copy or a Block_release if an implementation provides initial automatic storage for Blocks. This is due to the inherent race condition of potentially several threads trying to update the shared variable and the need for synchronization around disposing of older values and copying new ones. Such synchronization is beyond the scope of this language specification.
For details on what a __block variable should compile to, see the Block Implementation Spec, section 2.3.
It means that the variable it is a prefix to is available to be used within a block.

How can code inside an Objective-C block reference the block object itself?

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?
__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 of strawberryFields 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.
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).
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.
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.
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);