Is it allowed to 'change'/abuse/override the signature of a block in Objective C as follows?
objective-c, objective-c-blocks
Solution
The underlying reasons this works is a combination of:
[1] Objective-C (and C) is not strongly typed at compile time. While warnings may be produced by the compiler they can usually be silenced by (sometimes type unsafe) casts. Your assignment in this case is invalid as you are assigning a block reference which declares it requires an argument value compatible with `NSNumber *` to another block reference which only declares it requires an argument value compatible with `id`. This is type unsafe and will produce runtime errors sometimes, see below.
[2] Objective-C runtime message passing is dynamic, that is the target code for a message is determined as the code runs. This means as all your uses of `number` in the block are non-specific to `NSNumber` when you pass an `NSDate` at runtime suitable methods are still located dynamically. However change your `bar` to:
void (^bar)(NSNumber *) = ^(NSNumber *number)
{
NSLog(@"Value is %@, class is %@, int value is %d.", number, [number class], [number intValue]);
};
and you will see runtime errors.
[3] Both `[NSNumber numberWithInt:10]` and `[NSDate date`] are declared to return values of type `id`, not `NSNumber *` & `NSDate *` as you might expect. This means you don't need `foo`, you can just type:
bar([NSDate date]);
and get the same result without any warnings... As a further example consider this:
NSNumber *num = [NSNumber numberWithInt:3];
NSDate *date = num; // produces a warning
id erase = num; // erase type info and do...
date = erase; // effectively the same assignment, no warning
Take way: Objective-C is not a type safe language, the compiler will in many cases warn you about potential problems, but it will not do so in all cases.
Problem
Is this allowed and why? ``` void (^bar)(NSNumber *) = ^(NSNumber *number) { NSLog(@"Value is %@, class is %@.", number, [number class]); }; bar([NSNumber numberWithInt:10]); void (^foo)(id) = bar; foo([NSDate date]); ``` Output is: ``` Value is 10, class is __NSCFNumber. Value is 2012-05-17 18:54:14 +0000, class is __NSDate. ``` I couldn't find anything related that explains this. Can you provide a link to the objective c blocks specification that covers this? Currently I'm working on a block based UITableView subclass and it would make things a lot easier, if I'm safe to use this.