42

我想获取 NSNumber 实例的类型。

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

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

 if ([[myNum className] isEqualToString:@"NSCFNumber"]) {
  // 将 NSNumber 处理为整数
 } else if ([[myNum className] isEqualToString:@"NSCFBoolean"]) {
  // 将 NSNumber 处理为布尔值
 }

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

4

12 回答 12

75

我建议使用该-[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");
}

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

于 2010-03-25T19:42:07.060 回答
49

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

CFNumberType numberType = CFNumberGetType((CFNumberRef)someNSNumber);

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;
于 2011-10-13T00:27:32.947 回答
30

如果你只想区分布尔值和其他任何东西,你可以利用布尔 NSNumbers 总是返回一个共享实例的事实:

NSNumber *num = ...;
if (num == (void*)kCFBooleanFalse || num == (void*)kCFBooleanTrue) {
   // num is boolean
} else {
   // num is not boolean
}
于 2013-04-30T09:38:27.407 回答
9

NSNumber explicitly doesn't guarantee that the returned type will match the method used to create it, so doing this at all is probably a bad idea.

However, you could probably do something like this (you could also compare to objc_getClass("NSCFNumber") etc., but this is arguably more portable):

Class boolClass = [[NSNumber numberWithBool:YES] class];
/* ... */
if([myNum isKindOfClass:boolClass]) {
  /* ... */
}
于 2010-03-27T03:55:44.527 回答
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"];
}

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

于 2015-12-14T14:05:07.963 回答
5

在斯威夫特:

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
}
于 2016-12-06T16:17:01.793 回答
4

编译器警告您并且它不起作用的原因是因为-[NSObject className]在 Mac OS X 上的 NSObject 类别中声明(在 NSScriptClassDescription.h 中),而不是在 iPhone 上声明。(显然,它不支持 AppleScript。)NSStringFromClass([myNum class])您应该使用它来确保在所有平台上的安全。奇怪的是,它-className被声明为一个简单的包装器NSStringFromClass()......

于 2010-03-25T19:48:57.290 回答
3
NSString *classString = NSStringFromClass([myNum class]);

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

于 2010-03-25T19:36:25.107 回答
0

检查 NSNumber 是否包含布尔值试试这个:

if (strcmp([myNumber objCType], [@(YES) objCType]) == 0)
NSLog(@"%@", [myNumber boolValue] ? @"true" : @"false");
于 2016-08-27T06:19:42.120 回答
-1

objCType文件指出The returned type does not necessarily match the method the number object was created with

其次,将数字类与给定类类型进行比较或假设布尔数字实例是共享单例的其他方法没有记录在案。

一种更可靠(虽然不完全)的方法是依赖 NSJSONSerialisation,因为它正确识别使用 bool 创建的数字实例并在 json 中输出 true/false。这是我们可以期待 Apple 在使用新的 SDK 和不同的架构时处理的事情。下面是代码:

+(BOOL) isBoolType:(NSNumber*) number {

    NSError* err;
    NSData* jsonData = [NSJSONSerialization dataWithJSONObject:@{@"key":number}
                                                       options:0
                                                         error:&err];

    NSString* jsonString = [[NSString alloc] 
                              initWithData:jsonData
                                  encoding:NSUTF8StringEncoding];

    return [jsonString containsString:@"true"]
            || [jsonString containsString:@"false"];

}
于 2017-05-18T14:40:35.690 回答
-1

斯威夫特版本

NSNumber是一个类簇,因此每个底层类型都可以从实例中计算出来。此代码通过创建预期类型的​​实例,然后将其与未知类型进行比较来避免对不同的 NSNumber 类型进行硬编码。

extension NSNumber {
    var isBool: Bool {
        return type(of: self) == type(of: NSNumber(booleanLiteral: true))
    }
}
于 2018-04-04T02:41:52.070 回答
-2

检查对象是 NSNumber 类型:

if([obj isKindOfClass:NSClassFromString(@"__NSCFNumber")]) { //NSNumber }

于 2014-02-26T11:33:26.847 回答