获取NSNumber的类型

oka*_*ami 36 objective-c nsnumber

我想获得NSNumber实例的类型.

我在http://www.cocoadev.com/index.pl?NSNumber上发现了这个:

 NSNumber *myNum = [[NSNumber alloc] initWithBool:TRUE];

 if ([[myNum className] isEqualToString:@"NSCFNumber"]) {
  // process NSNumber as integer
 } else if  ([[myNum className] isEqualToString:@"NSCFBoolean"]) {
  // process NSNumber as boolean
 }

好的,但这不起作用,编译器无法识别[myNum className].我正在为iPhone编译.

Dav*_*ong 77

我建议使用该-[NSNumber objCType]方法.

它允许你做:

NSNumber * n = [NSNumber numberWithBool:YES];
if (strcmp([n objCType], @encode(BOOL)) == 0) {
    NSLog(@"this is a bool");
} else if (strcmp([n objCType], @encode(int)) == 0) {
    NSLog(@"this is an int");
}
Run Code Online (Sandbox Code Playgroud)

有关类型编码的更多信息,请查看Objective-C运行时参考.

  • 这不起作用 - 至少在iOS上:(lldb)p(char*)[[NSNumber numberWithBool:YES] objCType] - 它在内部将bool编码为char(在机器级别是正确的,但不是在机器级别故意水平) (17认同)
  • 此信息已过时,它不适用于64位iOS设备和模拟器,因此不应使用它.它可能导致很难找到只会在64位iOS设备上出现的问题. (10认同)
  • 该文档指出了一个非常重要的特殊考虑因素:"返回的类型不一定与创建数字对象的方法相匹配." (3认同)

Chr*_*ris 44

您可以通过这种方式获取类型,无需进行字符串比较:

CFNumberType numberType = CFNumberGetType((CFNumberRef)someNSNumber);
Run Code Online (Sandbox Code Playgroud)

numberType将是以下之一:

enum CFNumberType {
   kCFNumberSInt8Type = 1,
   kCFNumberSInt16Type = 2,
   kCFNumberSInt32Type = 3,
   kCFNumberSInt64Type = 4,
   kCFNumberFloat32Type = 5,
   kCFNumberFloat64Type = 6,
   kCFNumberCharType = 7,
   kCFNumberShortType = 8,
   kCFNumberIntType = 9,
   kCFNumberLongType = 10,
   kCFNumberLongLongType = 11,
   kCFNumberFloatType = 12,
   kCFNumberDoubleType = 13,
   kCFNumberCFIndexType = 14,
   kCFNumberNSIntegerType = 15,
   kCFNumberCGFloatType = 16,
   kCFNumberMaxType = 16
};
typedef enum CFNumberType CFNumberType;
Run Code Online (Sandbox Code Playgroud)

  • 不幸的是,没有kCFNumberBoolType来区分布尔值和字符,因此这并不适用于所有情况. (16认同)

Jak*_*ger 27

如果您只想区分布尔值和其他任何东西,您可以利用布尔NSNumbers始终返回共享实例的事实:

NSNumber *num = ...;
if (num == (void*)kCFBooleanFalse || num == (void*)kCFBooleanTrue) {
   // num is boolean
} else {
   // num is not boolean
}
Run Code Online (Sandbox Code Playgroud)

  • +1 的独创性,但我不推荐它用于生产代码(解决方案太脆弱了......) (2认同)
  • 你甚至可以使用`if(num == @(YES)|| num == @(NO))`.但是使用Core Foundation常量看起来非常复杂,而将Objective C对象与`==`进行比较看起来像是一个新手错误;) (2认同)

小智 9

NSNumber明确地不保证返回的类型将与用于创建它的方法匹配,因此这样做可能是一个坏主意.

但是,你可能会做这样的事情(你也可以比较objc_getClass("NSCFNumber")等等,但这可以说是更便携):

Class boolClass = [[NSNumber numberWithBool:YES] class];
/* ... */
if([myNum isKindOfClass:boolClass]) {
  /* ... */
}
Run Code Online (Sandbox Code Playgroud)


cnc*_*ool 5

使用方法-[NSNumber objCType] method获取类型。

如果类型等于@encode(BOOL),或者数字本身是kCFBooleanFalse 或kCFBooleanTrue,则它是一个布尔值。

如果它不是 'c' 以外的任何东西,它就是一个数字。

如果它是'c',那么似乎是唯一受支持的方式,不检查私有类名,或与未记录的单例进行比较,是转为一个元素的数组,数字,然后使用 NSJSONSerialization 来获取字符串表示。最后,检查字符串表示是否包含字符串“true”或“false”。这是检查 NSNumber 是否为 BOOL 的完整代码:

-(BOOL)isBool
{
    if(!strcmp(self.objCType, @encode(BOOL)) ||
        self == (void*)kCFBooleanFalse ||
        self == (void*)kCFBooleanTrue)
    {
        return YES;
    }

    if(strcmp(self.objCType, "c"))
    {
        return NO;
    }

    NSString * asString = [[NSString alloc] initWithData:[NSJSONSerialization dataWithJSONObject:@[self] options:kNilOptions error:nil] encoding:NSUTF8StringEncoding];

    return [asString containsString:@"true"] || [asString containsString:@"false"];
}
Run Code Online (Sandbox Code Playgroud)

请注意,使用 NSJSONSerialization 很慢,并且如果 @NO/@YES 停止始终等于 kCFBooleanFalse/kCFBooleanTrue,则可能不应该在紧密循环中使用此方法。


Chi*_*buZ 5

在Swift中:

let numberType = CFNumberGetType(answer)

switch numberType {
case .charType:
    //Bool
case .sInt8Type, .sInt16Type, .sInt32Type, .sInt64Type, .shortType, .intType, .longType, .longLongType, .cfIndexType, .nsIntegerType:
    //Int
case .float32Type, .float64Type, .floatType, .doubleType, .cgFloatType:
    //Double
}
Run Code Online (Sandbox Code Playgroud)


Ale*_*yne 3

NSString *classString = NSStringFromClass([myNum class]);
Run Code Online (Sandbox Code Playgroud)

这应该是你想要的字符串。