@interface AQBlog : NSBlog @end

Tutorials, musings on programming and ePublishing

A Blocks Gotcha

Permalink

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.

Comments