我想获得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编译。
我建议使用-[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 Runtime Reference。
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"];
}
NSNumber
是一个class-cluster,因此每个底层类型都可以从实例中找到。此代码通过创建期望类型的实例,然后将其与未知类型进行比较,避免对不同NSNumber类型进行硬编码。
extension NSNumber {
var isBool: Bool {
return type(of: self) == type(of: NSNumber(booleanLiteral: true))
}
}
check对象是NSNumber类型:
if([obj isKindOfClass:NSClassFromString(@"__NSCFNumber")])
{
//NSNumber
}
您可以通过这种方式获取类型,无需进行字符串比较:
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;
如果您只想区分布尔值和其他任何东西,您可以利用布尔NSNumbers总是返回共享实例的事实:
NSNumber *num = ...;
if (num == (void*)kCFBooleanFalse || num == (void*)kCFBooleanTrue) {
// num is boolean
} else {
// num is not boolean
}
NSNumber明确地不保证返回的类型将与用于创建它的方法匹配,因此这样做可能是一个坏主意。
但是,你可能会做这样的事情(你也可以比较objc_getClass("NSCFNumber")
等,但这可以说是更便携):
Class boolClass = [[NSNumber numberWithBool:YES] class];
/* ... */
if([myNum isKindOfClass:boolClass]) {
/* ... */
}
在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
}
编译器警告你并且它不起作用的原因是因为-[NSObject className]
在Mac OS X上的NSObject(在NSScriptClassDescription.h中)中的类别中声明并且未在iPhone上声明。 (显然,它不支持AppleScript。)NSStringFromClass([myNum class])
是您应该在所有平台上安全使用的。可能的是,无论如何,-className
被宣布为围绕NSStringFromClass()
的简单包装...
使用-[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,则此方法可能不应该在紧密循环中使用。
NSString *classString = NSStringFromClass([myNum class]);
那应该得到你想要的字符串。
检查NSNumber是否包含bool值试试这个:
if (strcmp([myNumber objCType], [@(YES) objCType]) == 0)
NSLog(@"%@", [myNumber boolValue] ? @"true" : @"false");