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.
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 withid. 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
numberin the block are non-specific toNSNumberwhen you pass anNSDateat runtime suitable methods are still located dynamically. However change yourbarto:and you will see runtime errors.
[3] Both
[NSNumber numberWithInt:10]and[NSDate date] are declared to return values of typeid, notNSNumber *&NSDate *as you might expect. This means you don’t needfoo, you can just type:and get the same result without any warnings… As a further example consider this:
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.