I want to use Message Forwarding to let any unimplemented getter method return 0, instead of throw a unrecognized selector exception. Like
MyClass *r = [[MyClass alloc] init];
NSNumber *n = (NSNumber *)r;
NSLog(@"%d", [n integerValue]); // output 0
NSLog(@"%f", [n doubleValue]); // output 0.00000
NSLog(@"%@", [n stringValue]); // output (null)
So I wrote this example:
#pragma mark -
#pragma mark Application lifecycle
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
NSNumber *n = (NSNumber *)self;
NSLog(@"%d", [n integerValue]);
NSLog(@"%f", [n doubleValue]);
NSLog(@"%@", [n stringValue]);
return YES;
}
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
NSMethodSignature *ms = [super methodSignatureForSelector:aSelector];
if(ms)
return ms;
// Q = uint64_t, so it should also works for double which is also 64bit
return [NSMethodSignature signatureWithObjCTypes:"Q@:"];
}
- (void)forwardInvocation:(NSInvocation *)anInvocation {
uint64_t ZERO64 = 0;
[anInvocation setReturnValue:&ZERO64];
}
The output result on a real device is 0, 0.00000, (null), but on emulator, it's 0, NaN, (null)
So the double type does not work as expected. My first thought is change the NSMethodSignature to "d@:" (d is double)
The output result is right on both device and simulator, but there are something wierd happening on the simulator only. Run this code and it will crash on the 6th loop with some kind of CALayer exception:
#pragma mark -
#pragma mark Application lifecycle
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
for(NSInteger i = 0; i < 100; i++) {
NSInteger t = [(NSNumber *)self integerValue];
UIViewController *view = [[UIViewController alloc] init];
// it always crash on the 6th loop on this line**
UINavigationController *nc = [[UINavigationController alloc] initWithRootViewController:view];
}
return YES;
}
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
NSMethodSignature *ms = [super methodSignatureForSelector:aSelector];
if(ms)
return ms;
// we change to return double
return [NSMethodSignature signatureWithObjCTypes:"d@:"];
}
- (void)forwardInvocation:(NSInvocation *)anInvocation {
uint64_t ZERO64 = 0;
[anInvocation setReturnValue:&ZERO64];
}
I'm curious about two questions, why NaN is returned on emulator in the first example, and what happened on the second example?