Is it necessary to use __block type specifier for mutable objects altered in blocks? - objective-c

Say map is a NSDictioanry, my understanding is since the address of res does not change in the block we don't need to use __block for it. Is this correct?
//__block NSMutableArray *res = [#[] mutableCopy];
NSMutableArray *res = [#[] mutableCopy];
__block NSInteger i = 0;
[map enumerateKeysAndObjectsUsingBlock:^(NSString *key, NSArray *v, BOOL *stop) {
[res addObject:v];
i++;
}];
By the way I have run the code it works fine.

The __block type specifier is only necessary for the storage of mutable items which would normally go on the stack.
Since a block is not guaranteed to be called only within the scope of the method that creates it (this is called escaping), it might need to mutate variables which it references after they've gone away. References to things that go on the stack (like i in your example) can become dangling pointers if the block is held onto past the end of the original method or function, so if they are to be mutated, they need to be stored somewhere other than the stack. The __block specifier tells the compiler to put the variable in separate storage which will be valid whenever the block is called.
For things which are heap allocated (like res above), this is not necessary — since the pointer to the object will not change as long as the object is around (which it should be, since the block will retain it by default), the local storage of the object pointer does not need to be put in alternative storage, and can stay on the stack.
If you'd like to read more on this, the Blocks and Variables documentation page has in-depth info on memory management with blocks, and more on the __block storage type.

That is correct. __block is only necessary if you assign (= or equivalent) to the variable inside the block, or if you want to block to be able to see assignments to the variable outside the block after the block was created. (This is true regardless of what the variable's type is.)
Here, The variable i is assigned to inside the block, with the ++ operator, hence __block is necessary. The variable res is never assigned to anywhere; the variable res is read from (not assigned to) inside the block.

Related

When *exactly* is it necessary to copy a block in objective-C under ARC?

I've been getting conflicting information about when I need to copy a block when using ARC in objective-C. Advice varies from "always" to "never", so I'm really not sure what to make of it.
I happen to have a case I don't know how to explain:
-(RemoverBlock)whenSettledDo:(SettledHandlerBlock)settledHandler {
// without this local assignment of the argument, one of the tests fails. Why?
SettledHandler handlerFixed = settledHandler;
[removableSettledHandlers addObject:handlerFixed];
return ^{
[removableSettledHandlers removeObject:handlerFixed];
};
}
Which is called with a block inline like this:
-(void) whatever {
[self whenSettledDo:^(...){
...
}];
}
(The actual code this snipper was adapted from is here.)
What does copying the argument to the local variable change here? Is the version without the local making two distinct copies, one for addObject and one for removeObject, so the removed copy doesn't match the added copy?
Why or when isn't ARC handling blocks correctly? What does it guarantee and what are my responsibilities? Where is all of this documented in a non-vague fashion?
In C, correctness cannot be inferred from running any number of tests, because you could be seeing undefined behavior. To properly know what is correct, you need to consult the language specification. In this case, the ARC specification.
It is instructive to first review when it is necessary to copy a block under MRC. Basically, a block that captures variables can start out on the stack. What this means is when you see a block literal, the compiler can replace it with a hidden local variable in that scope that contains the object structure itself, by value. Since local variables are only valid in the scope they are declared in, that is why blocks from block literals are only valid in the scope the literal is in, unless it is copied.
Furthermore, there is the additional rule that, if a function takes a parameter of block pointer type, it makes no assumptions about whether it's a stack block or not. It is only guaranteed that the block is valid at the time the block is called. However, this pretty much means that the block is valid for the entire duration of the function call, because 1) if it is a stack block, and it is valid when the function was called, that means somewhere up the stack where the block was created, the call is still within the scope of the stack literal; therefore it will still be in scope by the end of the function call; 2) if it is a heap block or global block, it is subject to the same memory management rules as other objects.
From this, we can deduce where it is necessary to copy. Let's consider some cases:
If the block from a block literal is returned from the function: It needs to be copied, since the block escapes from the scope of the literal
If the block from a block literal is stored in an instance variable: It needs to be copied, since the block escapes from the scope of the literal
If the block is captured by another block: It does not need to be copied, since the capturing block, if copied, will retain all captured variables of object type AND copy all captured variables of block type. Thus, the only situation where our block would escape this scope would be if the block that captures it escapes the scope; but in order to do that, that block must be copied, which in turn copies our block.
If the block from a block literal is passed to another function, and that function's parameter is of block pointer type: It does not need to be copied, since the function does not assume that it was copied. This means that any function that takes a block and needs to "store it for later" must take responsibility for copying the block. And indeed this is the case (e.g. dispatch_async).
If the block from a block literal is passed to another function, and that function's parameter is not of block pointer type (e.g. -addObject:): It needs to be copied if you know that this function stores it for later. The reason it needs to be copied is that the function cannot take responsibility for copying the block, since it does not know it is taking a block.
So if your code in the question was in MRC, -whatever would not need to copy anything. -whenSettledDo: will need to copy the block, since it is passed to addObject:, a method that takes a generic object, type id, and doesn't know it's taking a block.
Now, let's look at which of these copies ARC takes care for you. Section 7.5 says
With the exception of retains done as part of initializing a __strong
parameter variable or reading a __weak variable, whenever these
semantics call for retaining a value of block-pointer type, it has the
effect of a Block_copy. The optimizer may remove such copies when it
sees that the result is used only as an argument to a call.
What the first part means is that, in most places where you assign to a strong reference of block pointer type (which normally causes a retain for object pointer types), it will be copied. However, there are some exceptions: 1) In the beginning of the first sentence, it says that a parameter of block pointer type is not guaranteed to be copied; 2) In the second sentence, it says that if a block is only used as an argument to a call, it is not guaranteed to be copied.
What does this mean for the code in your question? handlerFixed is a strong reference of block pointer type, and the result is used in two places, more than just an argument to a call, thus assigning to it assigns a copy. If however, you had passed a block literal directly to addObject:, then there is not guaranteed to be a copy (since it's used only as an argument to a call), and you would need to copy it explicitly (as we discussed that the block passed to addObject: needs to be copied).
When you used settledHandler directly, since settledHandler is a parameter, it is not automatically copied, so when you pass it to addObject:, you need to copy it explicitly, because as we discussed that the block passed to addObject: needs to be copied.
So in conclusion, in ARC you need to explicitly copy when passing a block to a function that doesn't specifically take block arguments (like addObject:), if it's a block literal, or it's a parameter variable that you're passing.
I've confirmed that my particular issue was in fact making two distinct copies of the block. Tricky tricky. This implies the proper advice is "never copy, unless you want to be able to compare the block to itself".
Here's the code I used to test it:
-(void) testMultipleCopyShenanigans {
NSMutableArray* blocks = [NSMutableArray array];
NSObject* v = nil;
TOCCancelHandler remover = [self addAndReturnRemoverFor:^{ [v description]; }
to:blocks];
test(blocks.count == 1);
remover();
test(blocks.count == 0); // <--- this test fails
}
-(void(^)(void))addAndReturnRemoverFor:(void(^)(void))block to:(NSMutableArray*)array {
NSLog(#"Argument: %#", block);
[array addObject:block];
NSLog(#"Added___: %#", array.lastObject);
return ^{
NSLog(#"Removing: %#", block);
[array removeObject:block];
};
}
The logging output when running this test is:
Argument: <__NSStackBlock__: 0xbffff220>
Added___: <__NSMallocBlock__: 0x2e283d0>
Removing: <__NSMallocBlock__: 0x2e27ed0>
The argument is an NSStackBlock, stored on the stack. In order to be placed in the array or the closure it must be copied to the heap. But this happens once for the addition to the array and once for the closure.
So the NSMallocBlock in the array has an address ending in 83d0 whereas the one in the closure that is removed from the array has an address ending in 7ed0. They are distinct. Removing one doesn't count as removing the other.
Bleh, guess I need to watch out for that in the future.
A block must be copied when the application leaves the scope where the block was defined. A bad example:
BOOL yesno;
dispatch_block_t aBlock;
if (yesno)
{
aBlock = ^(void) { printf ("yesno is true\n");
}
else
{
aBlock = ^(void) { printf ("yesno is false\n");
}
aBlock = [aBlock copy];
It's too late already! The block has left its scope (the { brackets } ) and things can go wrong. This could have been fixed trivially by not having the { brackets }, but it is one of the rare cases where you call copy yourself.
When you store a block away somewhere, 99.99% of the time you are leaving the scope where the block was declared; usually this is solved by making block properties "copy" properties. If you call dispatch_async etc. the block needs to be copied, but the called function will do that. The block based iterators for NSArray and NSDictionary typically don't have to make copies of the block because you are still running inside the scope where the block was declared.
[aBlock copy] when the block was already copied doesn't do anything, it just returns the block itself.

2D NSString array usage inside block method

Why am I not able to use this?
__block NSString *tableStrings[4][2];
[userValues enumerateObjectsUsingBlock:^(NSNumber *userScore, NSUInteger idx, BOOL *stop) {
tableStrings[idx][0] = #"< 5";
tableStrings[idx][1] = #"> 95";
}];
The compiler is yelling at me of "Cannot refer to declaration with an array type inside block". I was under the impression that denoting __block before the variable would allow this to be done. I can make it work with using NSString[x][x] but I'm curious as to why this is not allowed.
Blocks cannot access array variables of automatic or __block storage from the enclosing scope. That's just a restriction of blocks. It's because both of those things requires being able to copy the variable. And array type is not assignable.
It would be possible for them to make a special case for arrays, that arrays are copied element-by-element. C++11 lambdas makes this special case, so they can capture arrays by value, even though arrays are not assignable. However, the blocks people didn't bother to make this special case.

Should I use the __block specifier on an object pointer even though it works without it?

I am using a CAAnimation completion block (using CAAnimationBlocks) to provide processing at the end of an animation and part of that completion block modifies the animated CALayer. This works even if layer isn't declared with the __block specifier, given the object pointer remains constant, however I am really treating the object as read/write.
One aspect of the Apple Guide that bothers me is:
__block variables live in storage that is shared between the lexical scope of the variable and all blocks and block copies declared or
created within the variable’s lexical scope.
Given the layer is a collection iterator, that looks to me like it will actually break if I do use the __block specifier.
Here is the code in question:
for (CALayer *layer in _myLayers) // _myLayers is an ivar of the containing object
{
CAAnimationGroup *group = ...;
...
group.completion = ^(BOOL finished)
{
[CATransaction begin];
[CATransaction setValue:(id)kCFBooleanTrue
forKey:kCATransactionDisableActions];
layer.position = [self _findPosition];
[CATransaction commit];
[layer removeAnimationForKey:#"teleportEffect"];
};
[layer addAnimation:group forKey:#"teleportEffect"];
}
My actual question is: Am I doing this right (my spider sense is tingling).
EDIT I should also add that my app uses MRR, however there are no issues with retain/release given the layers are static in nature (their lifetime is that of the containing NSView). Also I appear to be doing precisely what the Patterns to Avoid section of the guide say I shouldn't do, although it's not clear (to me) why.
__block variables are mutable within the block (and the enclosing scope) and are preserved if any referencing block is copied to the heap.
I don't think that in your case you need a block variable because you are changing the value of the object layer inside the block, since it belong to the _myLayers array that seems to be an instance variable it is difficult that the object will be released before each block performed ... However you can add the __block storage type modifier to retain the object, but if you are using ARC, object variables are retained and released automatically as the block is copied and later released.
EDIT:
As to your concern with the Anti-patterns you mention, I think that in both anti-pattern examples, the critical point is the the variable declaration and the "block literal" assigned to it have different scope. Take the for case presented there:
void dontDoThis() {
void (^blockArray[3])(void); // an array of 3 block references
for (int i = 0; i < 3; ++i) {
blockArray[i] = ^{ printf("hello, %d\n", i); };
// WRONG: The block literal scope is the "for" loop
}
}
blockArray is visible within the whole method body;
in the for loop, you create a block; a block is an object (some storage in memory) and has an address; the block as an object has "stack-local data structure" (from the reference above), i.e., it is allocated on the stack when you enter the method;
the fact that the "block literal" is treated as a variable local to the for loop, means that that storage can be reused at each successive iteration;
the block addresses are assigned to blockArray elements;
when you exit the for loop, blockArray will contain addresses of blocks that are possibly not there anymore and/or have been overwritten at each step depending on what the compiler does to stack data structure created within a for scope.
Your case is different, since your local variable is also within the for scope, and it will not be visible outside of it.
The case presented as an anti-pattern is similar to this:
{
int array[3];
for (int i = 0; i < 3; ++i) {
int a = i;
array[i] = &a;
// WRONG: The block literal scope is the "for" loop
}
Very likely, the a variable within the for scope will be allocated on stack just once and then reused at each iteration of the loop. In principle, a (one copy) will be still there (I am not sure, actually, the C standard should be inspected) outside of the loop, but it is pretty clear that the meaning of that code is not really sensible.
OLD ANSWER:
__block variables live in storage that is shared between the lexical scope of the variable and all blocks and block copies declared or created within the variable’s lexical scope.
I think this can be better understood like this: the lexical scope of the __block variable and all blocks (as per above definition) will share the same storage for that variable. So, if one block (or the original lexical scope) modifies the variable (I mean here the variable pointing to the object), that change will be visible to all others.
Given this, one effect of declaring a variable as __block is that in the non-ARC case the object pointed-to by it will not be automatically retained by each block where it is passed into (with ARC, the retain is done also for __block variables).
Both when using ARC and not using ARC, you need to use the __block specifier when you want to change the variable value and want that all blocks use the new value. Imagine that you had a block to initialize your _myLayers ivar: in this case, you would need to pass the _myLayers variable into the block as a __block variable, so that it (vs. a copy of it) can be modified.
In your case, if you are not using ARC, then, it all depends on whether the object pointed to by layer will be still there when the block is executed. Since layer comes from _myLayers, this converts into whether the object owning _myLayers will be still there when the block is executed. The answer to this is normally yes, since the block we are talking about is the completion block for an animation on that layer. (It would have been different, say, if it were the completion block for a network request).
Hope this helps.

Will ARC tell me when I must use __block?

AFAIK, __block is used when you're changing, inside the block, the address that a variable (declared outside the block) points to.
But, what if I'm changing the value that the variable points to but the pointer stays the same? E.g., what if I have NSMutableArray *array and am just doing [array addObject:object] inside the block? In this case, I'm not changing the pointer array, but I'm changing the value it points to. So, must I still use __block in declaring NSMutableArray *array?
You only need __block if you are changing the value of the variable.
I.e. if you have:
NSArray* foo;
You only need __block if you change the value of foo. Now, keep in mind that foo is nothing more than "a pointer to a thing that is typed NSArray". I.e. foo is effectively a 64 bit or 32 bit integer, depending on platform. If you change that integer, you need __block. If you don't, you don't need __block.
So, no, you don't need __block to call addObject: on the array since you aren't actually changing the value of foo.
If you were to do something like foo = (expression);, then you'd need __block.
(note that this is one of the reasons why concurrent programming under OO is so damned hard... it is exceptionally hard to define the "domain of variance" for any given execution path)

how to initialize an object(NSObject subclass) at a specific address

Hi I need to initialize an NSObject at a particular location that I specify(through a void* pointer, for example). For a little bit of context, I am writing a sqlite3 aggregate function. To keep temporary results from this function, I have to call a sqlite3_aggregate_context function, which allocates a block of memory for me. I want to store an NSDecimalNumber at this location.
So far I have tried two approaches:
1)allocWithZone, by doing:
void *location = sqlite3_aggregate_context(...); //returns a block of allocated memory of a certain size
NSDecimalNumber *num = [[NSDecimalNumber allocWithZone:NSZoneFromPointer(location)] initWithInt:0];
This does not work because NSZoneFromPointer returns nil. Docs say that the arguments to this function must be a previously allocated pointer, which it is. I dont know if this means allocated using NSZoneMalloc/Calloc.
2)
id location = sqlite3_aggregate_function(...);
location = [[NSDecimalNumber alloc] init];
but this causes some kind of infinite recursion when freeing the memory...not sure what the deal is. A screenshot here:
http://dl.dropbox.com/u/3002073/Public%20Sync/sqlitefunctionissue.png
Any suggestions will be greatly appreciated!
You can't really determine reliably where an object is going to be created in memory. The NSZoneFromPointer fails for you because the sqlite3 API is not using zones to allocate its resources.
If you want to be able to pass a specific location, you should do so using a pointer to the object (so you are storing a pointer to a pointer basically). You can then read this information from your aggregate function and update it accordingly. Just make sure that you don't simply let your object be freed at the end of the call without taking care to release it (or you'll have a leak).
So, for example, you could do something like:
NSDecimalNumber** numberLocation = sqlite3_aggregate_context(...);
*numberLocation = [[NSDecimalNumber alloc] initWithDouble:25.0];
You now have a reference to your object stored in your special memory area and can access it any time:
NSDecimalNumber* storedNumber = *numberLocation;
NSDecimalNumber* computedNumber = [[NSDecimalNumber alloc] initWithDouble:[storedNumber doubleValue] * someComputation];
[storedNumber autorelease];
*numberLocation = computedNumber;
On the other hand, I agree with Mark; maybe this immutable class isn't the best solution to your problem?
Your first version is simply not going to work. NSZoneFromPointer only works when passed a pointer allocated from a zone. It's used so you can allocate an object from the same zone as some other object.
The second version ought to work, though it's difficult to tell without more context. What are you passing to sqlite3_aggregate_context as the size of the memory to allocate? And how are you freeing that memory when you're done?
The second version doesn't work because the "id" type is actually a pointer, so you're pointing it at the memory returned by sqlite3_aggregate_context(), then pointing it at the memory returned by alloc/init. You really need to store a pointer-to-pointer to get that to work the way you want.
NSDecimalNumber is an immutable class, so calling -init on it (as opposed to -initWithDecimal:) is just going to get you some default value. What sort of code are you using to replace the NSNumber with new values as the function progresses?
More to the point, why use NSDecimalNumber at all, as opposed to a C integer, or double, or whatever?