This Question references this Question:
How to simplify callback logic with a Block?
My header has these typedefs
typedef void (^StuffDoneBlock)(NSDictionary * parsedData);
typedef void (^StuffFailedBlock)(NSError * error);
And in init
stuffDoneCallback = Block_copy(done);
StuffFailedCallback = Block_copy(error);
In this paper its says that Block_copy is unnecessary. But then it needs a bridged cast.
The compiler message is at follows:
error: cast of block pointer type 'StuffDoneBlock' (aka 'void (^)(NSDictionary *__strong)') to C pointer type 'const void *' requires a bridged cast [4]
stuffDoneCallback = _bridge(Block_copy(done));
^~~~~~~~~~~~~~~~
/Developer-4.2/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator5.0.sdk/usr/include/Block.h:60:61: note: instantiated from:
#define Block_copy(...) ((__typeof(__VA_ARGS__))_Block_copy((const void *)(__VA_ARGS__)))
^~~~~~~~~~~~~~~~~~~~~~~~~~~
First off, why are you even using Block_copy()? Unless you're writing raw C, you should be calling -copy on the block instead, as in [done copy]. Secondly, ARC will copy blocks for you that need to live past their initialization scope[1], so you don't need to even call -copy anymore. The only "exception" is that block-typed properties still need to have the copy attribute.
[1]: Clarification appears to be needed here. ARC only implicitly copies blocks when the compiler sees that it needs to live past its initialization scope. This basically means when it's assigned to a variable that escapes the current scope (stack variable declared in a parent scope, instance variable, static, etc.). However, if it's passed as an argument to a method/function, the compiler does not do any automatic copying. Typically this isn't a problem because block-aware methods/functions that need to hold onto the block past the stack frame (dispatch_async(), completion blocks, etc.) will copy them for you. However, APIs that are not block-aware (such as NSArray) will not implicitly copy the block, since they expect that a simple -retain will do the trick. If you're passing your block to a non-block-aware API and the block needs to live past the current scope, you must use an explicit -copy.
Related
converting my project to ARC but says it can't due to the following error 'No matching function for call to pthread_create'. Here is the code it falls in, happens specifically on the line starting with pthread create. How can I fix this? It also says Candidate function not viable: no known conversion from 'NSString *' to 'void * _Nullable' for 4th argument in the sidebar underneath the error.
I've cut off the rest of the function but can provide more detail if necessary.
void World::loadWorld(std::string name)
{
if(doneLoading==0)
{
doneLoading=1;
Resources::getResources->stopMenuTune();
if(LOW_MEM_DEVICE)
{
menu->deactivate();
Resources::getResources->unloadMenuTextures();
terrain->allocateMemory();
terrain->loadTerrain(name,TRUE);
doneLoading=2;
hud->fade_out=1;
}
else
{
terrain->allocateMemory();
pthread_t foo;
pthread_create(&foo,NULL,loadWorldThread, nsstring(name));
}
}
As your error message indicates the 4th argument to pthread_create is of type void *. Under ARC you cannot simply pass an Obj-C object reference as a void * as ARC would is not able to track the reference once it is stored in a C(++) pointer variable, and therefore cannot manage the object's memory.
For situations where an Obj-C reference must be passed into the C(++) world a bridge cast can be used to inform ARC how the memory should be managed. However in your case there a better way, just pass the C++ pointer, name, without creating an NSString. If loadWorldThread expects a std::string that is the correct thing to do anyway. If it expects an NSString * then either:
modify it to take a std::string and do any required conversion to NSString * within it; or
write a small intermediate function which takes a std::string, produces an NSString * from it, and then calls loadWorldThread. Pass this new function to pthread_create.
Doing either of the above avoids the use of a bridge cast in the pthread_create call to move the Obj-C reference into the C(++) world and out of ARC control; and another bridge cast in loadWorldThread (or intermediate function as above) to move it back into the Obj-C world and into ARC control.
Addendum
Expanding on the last paragraph, as the method there seems better suited to your situation. First, it is assumed that your code:
nsstring(name)
takes a value of type std::string and returns a value of type NSString, if it does not then look up how to do this conversion.
After the above expression you have a reference to an NSString under ARC control. You cannot simply pass such a reference as a void *, you must take it out of ARC's control first and take responsibility for its memory management (but not for long as you will see). You can bridge cast your NSString * to a CFStringRef:
CFStringRef cfName = (__bridge_retain CFStringRef)nsstring(name);
You can now pass cfName, which is a reference to a heap-allocated CFString, as a void *.
Now in loadWorldThread; which should be declared to take a void *, something like void loadWorldThread(void *arg) { ... }; you need to bridge cast your CFStringRef back to NSString * and hands responsibility for its memory management back to ARC:
NSString *nsName = (__bridge_transfer NSString *)arg;
The above is a standard pattern to pass an ARC controlled reference though an anonymous reference (void *).
(Note: the above uses CFStringRef to make it clear that you are passing around a reference to a manually managed CFString, you can cast directly to void * and back again, indeed you will notice that when casting back arg was not first cast to a CFStringRef to demonstrate this.)
HTH
In code that uses blocks, you frequently see declarations such as:
typedef void(^Thunk)(void);
Thunk block1 = ^{NSLog(#"%d %p",i, &i);};
instead of
typedef void(^Thunk)(void);
Thunk *block1 = ^{NSLog(#"%d %p",i, &i);};
Blocks seem to be the only Objective-C object that is handled directly, instead of through a pointer. Why is this? Aren't they regular objects?
If you're wondering about the missing *: In your example you typedef'd the block which is hiding the syntax. You can do this with other objects as well:
typedef NSNumber *Number;
Number foo = #42;
When assigning a block to a variable that's actually assigning a pointer.
Blocks are a bit like C arrays: Block literals are structures created by the compiler. Block variables are pointers behind the scenes.
You're not handling a block “directly”. You're handling it indirectly.
The syntax void (^)(void) declares a pointer to a block. There is no syntax for type “block”; there is only syntax for type “pointer to a block”.
From the Language Specification for Blocks:
The abstract declarator,
int (^)(char, float)
describes a reference to a Block that, when invoked, takes two parameters, the first of type char and the second of type float, and returns a value of type int. The Block referenced is of opaque data that may reside in automatic (stack) memory, global memory, or heap memory.
The relevant bit is “describes a reference to a Block”.
The specification isn't entirely consistent, since (for example) it refers to a “variable with Block type” and “Block variable declarations“. But in fact a variable always holds a reference (pointer) to a block, and never holds a block directly as its value.
If you look at the block implementation, you will see that blocks are ObjC objects.
If you inspect a stack block (like in your example), you'll see something like this:
(lldb) po myBlock
<__NSStackBlock__: 0xbfffc940>
And you will notice in the public header _Block_copy() and _Block_release() take void* arguments.
The non-pointeryness is just syntactic sugar the compiler provides to shield you from the dirty bits of blocks.
Blocks are a C extension. You can use blocks in C (where the extension is supported).
Apple just happens to have implemented blocks using ObjC types.
Implementation details: Blocks are one of the few ObjC types which may be allocated on the stack using clang. Normally, this is not an option because almost every API expects that an objc_object is a heap allocation which supports reference counting.
The clang analyzer can check for returning stack-based memory.
dispatch_block_t getPrintBlock (const char *msg) {
return ^{
printf("%s", msg);
};
}
raises this error: returning block that lives on the local stack
What does this error mean?
The error means you are returning a value which will be invalid after the method returns. This is not just an issue with blocks, consider:
- (int *) badMethod
{
int aLocalIntVariable;
return &aLocalIntVariable; // return a reference to aLocalIntVariable, but that variable is about to die...
}
Local variables are created when a method is entered, the place where they live is called the "stack". When a method returns those local variables are destroyed. You can return a value in such a variable, but you cannot return a reference to the variable itself - it will be invalid. You can pass a reference to a local variable to a method you call, as your local variable still exist in that case.
In your case you have created a block. Objective-C happens to create block values on the stack, i.e. effectively in an anonymous local variable, and refer to them using a reference. You can pass such a reference to a method you call, but you cannot return it - that anonymous local variable is destroyed just like any other.
However Objective-C provides you two ways to create a copy of a block value as an object, which lives on the "heap", and which will outlive its creator. First there is Block_copy which is a function:
<reference to heap allocated block> = Block_copy(<reference to stack allocated block>);
This is the original way to do this and is supported every - including in pure C code, blocks are part of C and not just Objective-C. The second way pretends the block is an object already and allows you to send the standard copy message:
<reference to heap allocated block> = [<reference to stack allocated block> copy];
If you are primarily an Objective-C person this second method probably feels more comfortable, but does blur the issue of why it is needed in the first place.
ARC helps here, in automating memory management it will automatically copy blocks from the stack to the heap (at least in current compilers, it may not work properly in earlier compilers) and so the programmer can ignore what is really an implementation detail.
Addendum: ARC
The last paragraph above was queried by #newacct and a long Q&A comment exchange resulted. In an attempt to make the information in that easier to follow we have both removed our comments and I have consolidated the information here as an addendum.
In understanding how ARC handles blocks two documents are useful:
Objective-C Automatic Reference Counting, in particular sections 3 (blocks are retainable object pointers), 3.2.3 (retainable object types are valid across return boundaries) and 7.5 (rules for when blocks are copied).
Transitioning to ARC Release Notes, in particular the FAQ item "How do blocks work in ARC?"
From these it can be determined that most of the time ARC will handle all copying of blocks from the stack to heap as part of its management of all object types.
The second reference highlights one case, that at least at the time the document was written, was not handled automatically. That case is where a stack allocated block is passed to a method parameter of type id, e.g. something like:
- (void) takeBlockWithTypeLoss:(id)block { ... }
[obj takeBlockWithTypeLoss:^{ ... }];
In such cases, at the time the document was written, ARC did not copy the block. If the called method then performs an operation which retains the passed block a problem occurs as the retain value is not on the heap. (Note that the block needs to be stack allocated for a problem to occur. Literal blocks which do not reference variables in their environment are statically allocated, also a literal block which is first stored in a local variable with default strong ownership and then passed to the method will be copied.)
This case is an example of type loss, a value known to be a block type is passed as id loosing type information. The compiler can always determine such points, so why does (or did..) ARC not copy the block? The answer given in the past is simply one of efficiency, the copy may not be required and lots of unneeded copies is a performance hit.
However the current compiler (Xcode 4.6.1) appears to handle this one remaining case, at the point of type loss a block is copied to the heap. If anyone can show this is now documented (or you are confident that your compiler handles this case e.g. by coding a check) then it would appear Block_copy() (or [block copy]) can be relegated to history, if not then when type loss occurs it should be used.
Addendum: June 2013
As revealed by this question there is a case that Xcode 4.6.3/Clang 4.2 does not handle. When a block is passed as one of the variable arguments to a variadic method then the compiler does not automatically promote a stack block to the heap. This is a subcase of type loss mentioned above.
So there is a case current compilers do not handle, which suggests a reason why the compiler supporting more than the specification is undocumented - that support is incomplete (though these is no theoretical reason that it needs to be).
So as before, if there is type loss then the compiler may not handle block promotion automatically (but this can be tested for if so desired), cases not involving type loss are handled automatically as per the specification.
(BTW. The older question mentioned in a comment to the question above is now one of the cases covered by the specification and handled correctly by the compiler.)
You need to make a copy of the block to move it to the heap.
i.e. something like:
dispatch_block_t createPrintBlock (const char *msg) {
return Block_copy(^{
printf("%s", msg);
}) ;
}
Can someone please explain to me the purpose of having __autoreleasing in the following sample code block?
- (void)execute:(NSError * __autoreleasing *)error {
// do stuff, possibly assigning error if something went wrong
}
I removed the __autoreleasing and everything still seems to compile/run fine. I started using obj-c post ARC so I never really learned/understood all those double underscore thingamajigs. I've read the ARC transition guide, but I don't fully understand their NSError example.
Consider how ARC works with variables - each reference variable has a mode (implicit or explicit): strong, weak, etc. This mode let's ARC know how to handle reads and writes to that variable; e.g. for a strong variable reading requires no additional action while writing requires releasing the existing reference in the variable before it is replaced by the new one. ARC needs to know the mode of any variable in order to function.
Now consider variables that themselves are passed by reference, e.g. for your execute you'll have a call along the lines of:
NSError *myError = nil;
...
[someObject execute:&myError]; // pass the variable itself by reference, not the variables value
and the body of execute will contain an assignment along the lines of:
- (void)execute:(NSError * __autoreleasing *)error
{
...
if (error != NULL)
*error = [NSError ...]; // assign indirectly via the reference to a variable
...
}
Now for that indirect assignment ARC needs to know the mode of the referenced variable so it knows how to read and write. That is what the __autoreleasing is in the declaration, it tells ARC that it has been passed a reference to a variable whose mode is autoreleasing, and that tells ARC how to read and write the contents of the variable. Remove the __autoreleasing and a default mode will be assumed, and in this case I'd suggest being explicit is certainly good.
The autoreleasing mode means the variable contains a reference which is not owned, reads should retain if necessary and writes can just write. It is used mainly for variables passed by reference.
You might notice that in the example above the variable myError has mode strong (implicitly) and yet it is passed by reference as autoreleasing - the compiler handles this automatically by introducing a temporary autoreleasing variable, copying without retaining the current reference in myError into it, and passing the temporary by reference as the argument to execute:. After the call returns the compiler does a normal assignment from the temporary to myError, which results in any old reference being released and the returned one retained.
For more details see Apple's Transitioning to ARC Release Notes
Followup to Comments
Q: Is __autoreleasing implicitly set?
A: Well Apple's document is not specific, but the Clang documentation says it is implicit for indirect parameters. As above I'd recommend being explicit, clarity is a Good Thing™.
Q: Does the placement matter?
A: Yes, and no... This is a C declaration, the stuff of quiz questions ("What does the following declare..."). The qualifier should be between the two asterisks as it is a pointer to a (variable of type) autoreleasing pointer to an object, but Apple state the compiler is "forgiving" without being specific of what it forgives. Play it safe, put it in the right place.
Q: Should you not test for error being NULL before doing the indirect assignment?
A: Of course you should, somewhere before you do the indirection. The code shown is just an outline and such detail was elided and covered by the ...’s. However as it has been raised a few times over the years maybe I elided too much, a suitable if has been added.
Assume the following code under ARC,
typedef void (^MyResponseHandler) (NSError *error);
#interface MyClass : NSObject
{
MyResponseHandler _ivarResponseHandler;
}
- (void)myMethod:(MyResponseHandler)responseHandler
{
_ivarResponseHandler = responseHandler;
...
}
Question: Is the block automatically copied to the heap when assigned to the ivar?
My previous question implied that it is copied when assigned through a #property. But, today I used the above code and received an EXC_BAD_ACCESS that was fixed by changing to
_ivarResponseHandler = [responseHandler copy].
Edit: My previous answer was likely wrong.
Some selected excerpts from the ARC docs say:
3. Retainable object pointers
A retainable object pointer (or retainable pointer) is a value of a retainable object pointer type (retainable type). There are three kinds of retainable object pointer types:
block pointers (formed by applying the caret (^) declarator sigil to a function type)
4.2. Semantics
Assignment occurs when evaluating an assignment operator. The semantics vary based on the qualification:
For __strong objects, the new pointee is first retained; second, the lvalue is loaded with primitive semantics; third, the new pointee is stored into the lvalue with primitive semantics; and finally, the old pointee is released. This is not performed atomically; external synchronization must be used to make this safe in the face of concurrent loads and stores.
4.4.1. Objects
If an object is declared with retainable object owner type, but without an explicit ownership qualifier, its type is implicitly adjusted to have __strong qualification.
7.5. Blocks
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.
So I think the answer is maybe, depending on the optimizer.
Your problem and solution indicate that my answer to your other question was probably wrong. I based it on the last paragraph of section 7.5 of the clang Objective-C Automatic Reference Counting documentation:
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.
I took “these semantics” to mean the whole document, but if “these semantics” to refers to only section 7.5, then ARC only inserts a Block_copy for a block that is captured by a block.