来自NSMethodSignature的BOOL编码错误

hri*_*.to 5 objective-c ios ios7 ios8

使用[NSMethodSignature getArgumentTypeAtIndex]函数时,我遇到了很奇怪的行为.根据objective-c 类型编码,它返回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
}
Run Code Online (Sandbox Code Playgroud)

令人惊讶的是(至少对男性而言)打印出以下内容:

来自NSMethodSignature的BOOL arg:@

来自objc/runtime.h的BOOL arg:B

我目前正在使用我自己的实现来避免这种奇怪的行为,但我想知道我是否遗漏了某些东西或者它只是一个bug.我唯一的线索是BOOL是原始的,就像这样,在调用objective-c方法时不能直接使用它.但是,当我尝试检查它[object isKingOfClass:[NSNumber class]]时返回NO.

UPDATE

好的我已将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
Run Code Online (Sandbox Code Playgroud)

这是真棒,但对于模拟器iPhone4s,我得到的真实设备iPhone5:

argument 2: -------- -------- -------- --------
        type encoding (c) 'c'
        flags {isSigned}

BOOL arg from NSMethodSignature: c
BOOL arg from objc/runtime.h: c
Run Code Online (Sandbox Code Playgroud)

我很确定如果我检查iPhone5s它将获得与iPhone6相同的输出(因为我认为这都是关于64位架构).所以我现在的问题是如何正确地解决旧设备,如何区分BOOL的char?或者我应该假设如果编码是'c'并且参数等于'1'我们有YES,而对于'0'我们有NO?

gab*_*ler 5

char *buf1 = @encode(BOOL);
NSLog(@"bool type is: %s", buf1);
Run Code Online (Sandbox Code Playgroud)

在32位模拟器上,encode(BOOL)返回'c',而在64位时,它返回'B'.在Build Settings中,将Architectures更改为$(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
Run Code Online (Sandbox Code Playgroud)

32位中的BOOL是一种签名字符.您可以将它与unsigned char区分开来.

@encode(char) --> 'c'
@encode(unsigned char) --> 'C'
Run Code Online (Sandbox Code Playgroud)

你可以从这里告诉设备是32位还是64位,如果是32位,'c'对BOOL检查有效.