3

I defined a block that takes an NSString and returns a NSURL for that string:

id (^)(id obj)

I've used typedef to make it a block with a name:

typedef id (^URLTransformer)(id);

And the following method does not work:

+ (URLTransformer)transformerToUrlWithString:(NSString *)urlStr
{
    return Block_copy(^(id obj){
        if ([obj isKindOfClass:NSString.class])
        {
            NSString *urlStr = obj;
            return [NSURL URLWithString:[urlStr stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
        }
        return nil; // **THIS LINE FAILS**
    });
}

Error:

Return type 'void *' must match previous return type 'id' when block literal has unspecified explicit return type

My question is: 1. how to correctly implement the method 2. how to implement the method without typedef URLTransformer?

Thanks

Carl Veazey
  • 18,392
  • 8
  • 66
  • 81
hzxu
  • 5,753
  • 11
  • 60
  • 95

2 Answers2

3

1.

You can either cast it to id or add type to block. I asked similar question before and quote from the answer

The correct way to remove that error is to provide a return type for the block literal:

id (^block)(void) = ^id{
    return nil; 
};

in your case

+ (URLTransformer)transformerToUrlWithString:(NSString *)urlStr
{
    return Block_copy(^id(id obj){ // id here
        if ([obj isKindOfClass:NSString.class])
        {
            NSString *urlStr = obj;
            return [NSURL URLWithString:[urlStr stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
        }
        return nil; // id here
    });
}

or

+ (URLTransformer)transformerToUrlWithString:(NSString *)urlStr
{
    return Block_copy(^(id obj){
        if ([obj isKindOfClass:NSString.class])
        {
            NSString *urlStr = obj;
            return [NSURL URLWithString:[urlStr stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
        }
        return (id)nil; // **THIS LINE FAILS**
    });
}

2.

To return block without typedef you can use similar syntax to return function pointer

+ (id (^)(id))transformerToUrlWithString:(NSString *)urlStr;

You can check more example from here.

PS: You should avoid Block_copy in ObjC code, use [block copy].

PS2: You mush be using ARC (otherwise so many leaks) and you don't need to copy block explicitly (in 99% of the cases, which includes this one).

PS3: Your should avoid id as much as possible, so your block should be typedef NSURL *(^URLTransformer)(NSString *);

Community
  • 1
  • 1
Bryan Chen
  • 45,816
  • 18
  • 112
  • 143
  • Hi it says 'Cast of block pointer type 'id(^)(__strong id)' to C pointer type 'const void *' requires a bridged cast, and if I do not use Block_copy it works with [... copy]. – hzxu Aug 22 '13 at 01:16
  • @hzxu what is your Xcode/Clang version? you can also cast `nil`. e.g. `return (id)nil;` – Bryan Chen Aug 22 '13 at 01:18
2

You can avoid typedef like this:

@interface Blah : NSObject
+(id (^)(id)) blockret;
@end

@implementation Blah
+(id (^)(id)) blockret {
    return ^(id obj) {
        return @"helo";
    };
}
@end

The type of your block is id (^)(id) - that's what goes into parentheses after the plus.

Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523