For your first question, this is what I found on the simulator
union { double d; uint64_t l; } u; NSNumber *n = (NSNumber *)self; ud = [n doubleValue]; NSLog(@"%f", ud); // nan NSLog(@"%llx",ul); // fff8000000000000 bzero(&u, sizeof(double)); NSLog(@"%f", ud); // 0.000000 NSLog(@"%llx",ul); // 0
Thus, instead of 0.0, NAN will be displayed (fff8000000000000).
To take a deeper look at what is different between [NSMethodSignature signatureWithObjCTypes:" d@ :"] and [NSMethodSignature signatureWithObjCTypes:" Q@ :"] see this
NSLog(@"%@\n%@", [[NSMethodSignature signatureWithObjCTypes:" Q@ :"] debugDescription], [[NSMethodSignature signatureWithObjCTypes:" d@ :"] debugDescription]);
Output
<NSMethodSignature: 0x74a0950> number of arguments = 2 frame size = 8 is special struct return? NO return value: -------- -------- -------- -------- type encoding (Q) 'Q' flags {} modifiers {} frame {offset = 0, offset adjust = 0, size = 8, size adjust = 0} memory {offset = 0, size = 8} argument 0: -------- -------- -------- -------- type encoding (@) '@' flags {isObject} modifiers {} frame {offset = 0, offset adjust = 0, size = 4, size adjust = 0} memory {offset = 0, size = 4} argument 1: -------- -------- -------- -------- type encoding (:) ':' flags {} modifiers {} frame {offset = 4, offset adjust = 0, size = 4, size adjust = 0} memory {offset = 0, size = 4} <NSMethodSignature: 0x74a1e80> number of arguments = 2 frame size = 8 is special struct return? NO return value: -------- -------- -------- -------- type encoding (d) 'd' flags {isFloat} <<<<----- this flag should be set if the return value is float type modifiers {} frame {offset = 0, offset adjust = 0, size = 8, size adjust = 0} memory {offset = 0, size = 8} argument 0: -------- -------- -------- -------- type encoding (@) '@' flags {isObject} modifiers {} frame {offset = 0, offset adjust = 0, size = 4, size adjust = 0} memory {offset = 0, size = 4} argument 1: -------- -------- -------- -------- type encoding (:) ':' flags {} modifiers {} frame {offset = 4, offset adjust = 0, size = 4, size adjust = 0} memory {offset = 0, size = 4}
You can see that the second method signature has flags {isFloat} on the return value. I am not an expert on x86 and AMR and low-level ObjC runtime. But I think that the CPU used this flag to determine the type of return value. Without installing it on the x86 CPU, the expected return value of the float is interpreted as NAN.
For your second question, I think this is due to the fact that you will inform at runtime that it will return a 64-bit size value, and thus, the 64-bit memory on the stack is reset. However, the caller expects a 32-bit return size (NSInteger). Therefore, some kind of stack flow occurs and leads to a failure.
I really implemented something similar, trying to make NSNull work like nil .
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector { NSMethodSignature *signature = [super methodSignatureForSelector:aSelector]; if (signature) return signature; const Class forwardClasses[] = {[NSNumber class], [NSString class], [NSArray class], [NSOrderedSet class]};