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.


© 2009-2019. All rights reserved.

Powered by Hydejack v9.1.6