使用[NSMethodSignature getArgumentTypeAtIndex]函数时,我遇到了很奇怪的行为。根据objective-c type encodings,它返回BOOL类型的'@'字符。如果我使用objc \ runtime.h库方法method_getTypeEncoding BOOL类型被正确表示为'B',但是我不明白为什么它不能使用更高级别的层NSMethodSignature。以下代码演示了问题:
-(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
}
以上令人惊讶的是(至少对男性而言)打印出以下内容:
来自NSMethodSignature的BOOL arg:@
来自objc / runtime.h的BOOL arg:B
我目前正在使用我自己的实现来避免这种奇怪的行为,但我想知道我是否遗漏了某些东西或者它只是一个bug。我唯一的线索是BOOL是原始的,就像这样,在调用objective-c方法时不能直接使用它。但是当我尝试检查它时[object isKingOfClass:[NSNumber class]]返回NO。
更新
好的我已将XCode更新到最新版本(6.1 6A1052d),情况大大改善。但是我现在的问题是将unsigned char编码与real bool编码区分开来。我知道在旧版本BOOL是typedef作为char,但我怎么能完成真正的char vs BOOL编码?我现在的结果是:
对于模拟器iPhone6 和真实设备 iPhone6 ,我收到了:
argument 2: -------- -------- -------- --------
type encoding (B) 'B'
flags {}
BOOL arg from NSMethodSignature: B
BOOL arg from objc/runtime.h: B
非常棒,但对于模拟器iPhone4s ,以及真正的设备 iPhone5 我得到了:
argument 2: -------- -------- -------- --------
type encoding (c) 'c'
flags {isSigned}
BOOL arg from NSMethodSignature: c
BOOL arg from objc/runtime.h: c
我很确定如果我检查iPhone5s它将获得与iPhone6相同的输出(因为我认为这完全是关于64位架构)。所以我现在的问题是如何正确地解决旧设备,如何区分BOOL的char?或者我应该假设如果编码是'c'并且参数等于'1'我们有YES,而'0'我们有NO?
答案 0 :(得分:5)
char *buf1 = @encode(BOOL);
NSLog(@"bool type is: %s", buf1);
在32位模拟器上,encode(BOOL)返回'c',而在64位时,它返回'B'。在构建设置中,将架构更改为$(ARCHS_STANDARD_32_BIT)
,然后它将为您返回'c'。
在objc / objc.h文件中。
#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
32位的BOOL是一种签名字符。您可以将它与unsigned char区分开来。
@encode(char) --> 'c'
@encode(unsigned char) --> 'C'
您可以告诉设备位于here的32位或64位,如果位于32位,则“c”对BOOL检查有效。
答案 1 :(得分:2)
我在调试器中的po [inv methodSignature]中得到了以下内容:
(lldb)po [inv methodSignature]
<NSMethodSignature: 0x7be7f660>
number of arguments = 3
frame size = 12
is special struct return? NO
return value: -------- -------- -------- --------
type encoding (v) 'v'
flags {}
modifiers {}
frame {offset = 0, offset adjust = 0, size = 0, size adjust = 0}
memory {offset = 0, size = 0}
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}
argument 2: -------- -------- -------- --------
type encoding (c) 'c'
flags {isSigned}
modifiers {}
frame {offset = 8, offset adjust = 0, size = 4, size adjust = -3}
memory {offset = 0, size = 1}
因为我打印出了NSLog
来自NSMethodSignature的BOOL arg:c
我无法发表评论,所以我写了这个答案。你可以请你的[inv methodSignature]吗?你可以在分配给encFromGetArgument
之后直接输出你的NSLog答案 2 :(得分:2)
根据@gabbler的答案,我设法检查参数是否是bool。以下代码适用于32位和64位架构:
-(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");
}
}