Ios NSMethodSignature中的布尔编码错误
我在使用[NSMethodSignature getArgumentTypeAtIndex]函数时遇到了非常奇怪的行为。它返回布尔类型的“@”字符,根据objective-c,该字符是错误的。如果我使用objc\runtime.h库方法,那么getTypeEncoding BOOL类型正确地表示为“B”,但是我不明白为什么它不能与更高级别的层NSMethodSignature一起工作。以下代码演示了该问题:Ios NSMethodSignature中的布尔编码错误,ios,objective-c,ios7,ios8,Ios,Objective C,Ios7,Ios8,我在使用[NSMethodSignature getArgumentTypeAtIndex]函数时遇到了非常奇怪的行为。它返回布尔类型的“@”字符,根据objective-c,该字符是错误的。如果我使用objc\runtime.h库方法,那么getTypeEncoding BOOL类型正确地表示为“B”,但是我不明白为什么它不能与更高级别的层NSMethodSignature一起工作。以下代码演示了该问题: -(void)viewDidAppear:(BOOL)animated { [s
-(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的布尔参数:@
来自objc/runtime.h的BOOL arg:B
我目前正在使用我自己的实现来避免这种奇怪的行为,但是我想知道我是否遗漏了什么或者这只是一个bug。我唯一的线索是BOOL是原始的,就像这样,在调用objective-c方法时不能直接使用它。但是,当我尝试检查它时,[objectiskingofclass:[NSNumber class]]返回NO
更新
好的,我已经将XCode更新到最新版本(6.1 6A1052d),情况大大改善。然而,我现在的问题是区分无符号字符编码和实布尔编码。我知道在旧版本中BOOL是作为char的typedef,但是如何实现真正的char与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位体系结构的)。所以我现在的问题是如何正确地解决旧设备,如何区分它们的布尔字符?或者我应该假设如果编码为“c”,参数等于“1”,我们有是,而对于“0”,我们没有?我从调试器中的po[inv methodSignature]中得到了以下信息: (lldb)采购订单【投资方法签字】
<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}
参数数量=3
框架尺寸=12
特殊结构是否返回?不
返回值:-------------------------------
类型编码(v)‘v’
标志{}
修饰语{}
帧{offset=0,offset adjust=0,size=0,size adjust=0}
内存{offset=0,size=0}
参数0:------------------------------
类型编码(@)@'
标志{isObject}
修饰语{}
帧{offset=0,offset adjust=0,size=4,size adjust=0}
内存{offset=0,size=4}
论据1:---------------------
类型编码(:)':'
标志{}
修饰语{}
帧{offset=4,offset adjust=0,size=4,size adjust=0}
内存{offset=0,size=4}
论据2:-------------------------
类型编码(c)‘c’
标志{isSigned}
修饰语{}
帧{offset=8,offset adjust=0,size=4,size adjust=-3}
内存{offset=0,size=1}
我用NSLog打印出来了
来自NSMethodSignature的布尔参数:c
我不能写评论,所以我写了这个答案。请您将您的[inv方法签名]?!在将NSLog分配给encFromGetArgument后,您是否可以直接输出NSLog
char *buf1 = @encode(BOOL);
NSLog(@"bool type is: %s", buf1);
在32位模拟器上,encode(BOOL)返回“c”,而在64位上,它返回“B”。在构建设置中,将架构更改为$(ARCHS\u标准\u 32\u位)
,然后它将为您返回“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位的布尔是一种有符号字符。您可以将其与无符号字符区分开来
@encode(char) --> 'c'
@encode(unsigned char) --> 'C'
您可以从中判断设备是32位还是64位,如果是32位,则“c”对布尔检查有效。基于@gabbler答案,我已设法检查参数是否为布尔。以下代码适用于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");
}
}
我无法回答您的问题,但是我不确定ARC将如何处理
[inv methodSignature]
返回的对象,您可以从该对象获得常量字符*
。很明显,缓冲区在对象域内(在其管理下),因此我认为您不应该创建临时对象并以这种方式取消引用它。因为methodSignature是Objective类,所以我非常确定它在ARC下可以正常工作。然而,问题的关键是它为什么返回错误的值。很可能是使用临时对象导致了这个问题。请尝试使用非临时变量。不,使用属性存储编码也没有帮助。仍然在寻找答案。我还注意到类型const char*被编码为“r*”,这是没有文档记录的(char*确实被编码为“*”,所以我猜在这种情况下“r”代表const。很好!根据你的回答,我找到了我的解决方案。在第一篇文章中看到我的更新。我看到了,很高兴它有所帮助。