I've encountered really odd behaviour when using [NSMethodSignature getArgumentTypeAtIndex] function. It returns me '@' character for BOOL type which in wrong according to objective-c type encodings. If I use objc\runtime.h library method method_getTypeEncoding BOOL type is correctly represented as a 'B', however I don't understand why it's not working with higher level layer NSMethodSignature. Following code demonstrates the problem:
-(void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
NSInvocation* inv = [NSInvocation invocationWithMethodSignature:[self methodSignatureForSelector:@selector(viewDidAppear:)]];
const char* encFromGetArgument = [[inv methodSignature] getArgumentTypeAtIndex:2];
const char* encFromMethodSignature = method_getTypeEncoding(class_getInstanceMethod([self class], @selector(viewDidAppear:)));;
const char* methodEncodingPure = [[[[NSString stringWithUTF8String:encFromMethodSignature] componentsSeparatedByCharactersInSet:[NSCharacterSet decimalDigitCharacterSet]] componentsJoinedByString:@""] UTF8String];//remove stack sizes
NSLog(@"BOOL arg from NSMethodSignature: %s", encFromGetArgument);
NSLog(@"BOOL arg from objc/runtime.h: %c", methodEncodingPure[3]);//first type is for return, second is target, third is selector
}
The above surprisingly(at least for men) prints the following:
BOOL arg from NSMethodSignature: @
BOOL arg from objc/runtime.h: B
I'm currently using my own implementation to avoid this odd behaviour however I want to know if I'm missing something or it's just a bug. My only clue is that BOOL is primitive and like this it cannot be used directly when calling objective-c methods. However when I try to check it [object isKingOfClass:[NSNumber class]] returns NO.
UPDATE
Ok I've update XCode to the latest version(6.1 6A1052d) and situation greatly improves. However my problem now is to distinguish unsigned char encoding from real bool encoding. I know in old versions BOOL is typedef as a char, but how I can accomplish real char vs BOOL encoding? My results now are:
For Simulator iPhone6 and real device iPhone6 I received:
argument 2: -------- -------- -------- --------
type encoding (B) 'B'
flags {}
BOOL arg from NSMethodSignature: B
BOOL arg from objc/runtime.h: B
which is awesome, however for simulator iPhone4s, and real device iPhone5 I'm getting:
argument 2: -------- -------- -------- --------
type encoding (c) 'c'
flags {isSigned}
BOOL arg from NSMethodSignature: c
BOOL arg from objc/runtime.h: c
I'm pretty sure that if I check iPhone5s it'll get the same output as iPhone6(as I think it's all about the 64-bit architecture). So my question now is how to properly workaround older devices, how to distinguish char of BOOL for them? Or should I just assume that if encoding is 'c' and argument is equal to '1' we have YES, and for '0' we have NO?
char *buf1 = @encode(BOOL);
NSLog(@"bool type is: %s", buf1);
On 32bit simulator, encode(BOOL) returns 'c', while on 64 bit, it returns a 'B'. In Build Settings, change Architectures to $(ARCHS_STANDARD_32_BIT)
, then it will returns 'c' for you.
in the objc/objc.h file.
#define OBJC_BOOL_DEFINED
/// Type to represent a boolean value.
#if !defined(OBJC_HIDE_64) && TARGET_OS_IPHONE && __LP64__
typedef bool BOOL;
#else
typedef signed char BOOL;
// BOOL is explicitly signed so @encode(BOOL) == "c" rather than "C"
// even if -funsigned-char is used.
#endif
BOOL in 32bit is a typeof signed char. You can distinguish it from unsigned char.
@encode(char) --> 'c'
@encode(unsigned char) --> 'C'
You can tell a device is in 32bit or 64bit from here,and if it is in 32 bit, 'c' is valid for BOOL check.
Based on the @gabbler answer I've managed to check if argument is bool or not. The following code works for both 32 and 64bit architecture:
-(void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
NSInvocation* inv = [NSInvocation invocationWithMethodSignature:[self methodSignatureForSelector:@selector(viewDidAppear:)]];
const char* encFromGetArgument = [[inv methodSignature] getArgumentTypeAtIndex:2];
if( 0 == strcmp(@encode(BOOL), encFromGetArgument) )
{
//BOOL val
NSLog(@"arg is bool");
}
else
{
//not BOOL
NSLog(@"arg is not bool");
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With