NSValue到NSNumber的转换崩溃



我想将NSValue转换为NSNumber。这个代码出了什么问题?

char value[4];
[myNSValue getValue:(void*)value];
NSNumber *number = [[NSNumber alloc] initWithBytes:(void*)value objCType:[myNSValue objCType]];
NSTimeInterval duration = [number intValue];

它导致最后一行发生崩溃。这里会发生什么?

正如上面评论中诊断的@ale0xB,NSNumber实际上并没有提供自己的-initWithBytes:objCType:方法的实现;因此,当您调用该选择器时,您实际上得到了来自NSNumber的基类NSValue的实现。[[NSNumber alloc] initWithBytes:foo objCType:bar][[NSValue alloc] initWithBytes:foo objCType:bar]之间没有1的区别——它们都调用相同的方法实现,该方法实现释放给定的self,并返回一个通常类型为NSConcreteValue的新对象(NSValue的未记录子类,但不是NSNumber的子类)。

更清楚地说:

#import <assert.h>
#import <Foundation/Foundation.h>
int main()
{
id x;
x = [NSNumber numberWithInt:42];
assert( [x isKindOfClass:[NSNumber class]] );
assert( [x respondsToSelector:@selector(intValue)] );
int fortytwo = 42;
x = [[NSNumber alloc] initWithBytes:&fortytwo objCType:@encode(int)];
assert(   [x isKindOfClass:[NSValue class]] );
assert( ! [x isKindOfClass:[NSNumber class]] );  // yikes!
assert( ! [x respondsToSelector:@selector(intValue)] );  // your particular problem
}

然而,类别拯救Martin Häcker编写了一个类别NSNumber(CreatingFromArbitraryTypes),可以根据您的需要进行调整。请在此处查看公共域源代码2基本思想是对每种可能的类型编码进行特殊情况处理:

  • 如果您正在尝试对"i"进行编码,则调度到-numberWithInt:
  • 如果您正在尝试对"f"进行编码,则分派到-numberWithFloat:

等等。这很乏味;但是,一旦编写了一次代码,就可以从那时起使用该类别,并简单地调用[NSNumber numberWithValue:myNSValue]

(1–或多或少。我认为,在这种情况下,没有显著差异。)

(2–该代码有几个错误,尤其是在以后的修订版中。请参阅我的补丁。)

请阅读我上面的评论以获得进一步的解释。

要实现您想要的,只需使用(char*)初始化一个NSString,然后调用NSString的intValue。-假设你知道类型,如果不看下面的评论-

干杯

最新更新