A Blocks Gotcha
So I was just writing some code, and I refactored it a bit by putting a little chunk into a block, then calling that block in multiple places. Here’s the gist of the original declaration:
NSXMLDocument * (^fetcher)(NSString *) = ^(NSString * typeName) {
NSArray * arguments = [NSArray arrayWithObjects: ...];
// fetch the data
NSXMLDocument * doc = ...;
if ( doc == nil )
{
LogError( ... );
return ( nil );
}
dispatch_async( dispatch_get_main_queue(), ^{
[progress setDoubleValue: [progress doubleValue] + step];
});
return ( doc );
};
Attempting to compile this, however, resulted in the following error from Clang:
error: incompatible block pointer types initializing 'void *(^)(NSString *)', expected
'NSXMLDocument *(^)(NSString *)'
NSXMLDocument * (^fetcher)(NSString *) = ^(NSString * typeName) {
^~~~~~~~~~~~~~~~~~~~~~~~
I scratched my head for a while over this, but it all came down to this line:
return ( nil );
It transpires that since MacTypes.h
(used by the Security framework in this case) #defines nil
as a synonym for NULL
, the preprocessor turns that into:
return ( (void *)0 );
Since that’s the first return statement in the block, the compiler creates a block with a void * return type. DOH. The solution was to type-cast the result:
return ( (NSXMLDocument *) nil );
It’s not the most elegant, and it would be nice if MacTypes.h
didn’t stomp all over ObjC’s nil
data type, but at least it works.