来自 NSMethodSignature 的 BOOL 编码错误
Posted
技术标签:
【中文标题】来自 NSMethodSignature 的 BOOL 编码错误【英文标题】:BOOL encoding wrong from NSMethodSignature 【发布时间】:2014-10-20 06:38:32 【问题描述】:我在使用 [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
我目前正在使用自己的实现来避免这种奇怪的行为,但是我想知道我是否遗漏了某些东西或者这只是一个错误。我唯一的线索是 BOOL 是原始的,像这样在调用objective-c方法时不能直接使用它。但是,当我尝试检查它时 [object isKingOfClass:[NSNumber class]] 返回 NO。
更新
好的,我已将 XCode 更新到最新版本(6.1 6A1052d),情况大大改善。但是我现在的问题是将无符号字符编码与真正的布尔编码区分开来。我知道在旧版本中 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 字符?或者我应该假设如果编码是'c'并且参数等于'1'我们有YES,而对于'0'我们有NO?
【问题讨论】:
我无法回答您的问题,但是我不确定 ARC 将如何处理[inv methodSignature]
返回的对象,您可以从中获得 const char *
。显然,该缓冲区在对象域内(在其管理下),所以我想您不应该创建一个临时对象并以这种方式取消引用它。
由于 methodSignature 是 ObjectiveC 类,我很确定它在 ARC 下可以正常工作。然而问题的重点是为什么它返回错误的值。
嗯,使用临时对象可能会导致问题。请尝试使用非临时变量。
不,使用属性存储编码也没有帮助。仍在寻找答案。我还注意到 const char* 类型被编码为 'r*' 没有记录(char* 确实被编码为 '*',所以我猜 'r' 在这种情况下代表 const。
【参考方案1】:
char *buf1 = @encode(BOOL);
NSLog(@"bool type is: %s", buf1);
在 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
32 位的 BOOL 是有符号字符的类型。您可以将其与 unsigned char 区分开来。
@encode(char) --> 'c'
@encode(unsigned char) --> 'C'
你可以从here判断设备是32位还是64位,如果是32位,'c'对BOOL检查有效。
【讨论】:
好点!根据您的回答,我找到了解决方案。在第一篇文章中查看我的更新。 我看过了,很高兴它有帮助。【参考方案2】:根据@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");
【讨论】:
【参考方案3】:我在调试器中的 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
我无法写评论,所以我写了这个答案。你能po你的[inv methodSignature]吗?!您能否在分配给 encFromGetArgument 后直接输出您的 NSLog
【讨论】:
以上是关于来自 NSMethodSignature 的 BOOL 编码错误的主要内容,如果未能解决你的问题,请参考以下文章