I want to get the type of NSNumber instance.
I found out on http://www.cocoadev.com/index.pl?NSNumber this:
NSNumber *myNum = [[NSNumber alloc] initWithB
objCType
documentation states that The returned type does not necessarily match the method the number object was created with
Secondly, other methods of comparing the class of number to a given class type or assuming boolean number instances to be shared singletons are not documented behaviour.
A more(not completely though) reliable way is to depend on NSJSONSerialisation as it correctly recognises number instances created with bool and outputs true/false in json. This is something we can expect Apple to take care of while moving with new SDKs and on different architectures. Below is the code:
+(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
is a class-cluster so each underlying type can be figured from the instance. This code avoids hard-coding the different NSNumber types by creating an instance of the expected type, and then comparing it against the unknown type.
extension NSNumber {
var isBool: Bool {
return type(of: self) == type(of: NSNumber(booleanLiteral: true))
}
}
In 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
}
check object is of NSNumber type :
if([obj isKindOfClass:NSClassFromString(@"__NSCFNumber")])
{
//NSNumber
}
You can get the type this way, no string comparisons needed:
CFNumberType numberType = CFNumberGetType((CFNumberRef)someNSNumber);
numberType will then be one of:
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;
The reason the compiler warns you and it doesn't work is because -[NSObject className]
is declared in a category on NSObject on Mac OS X (in NSScriptClassDescription.h) and not declared on iPhone. (It doesn't support AppleScript, obviously.) NSStringFromClass([myNum class])
is what you should use to be safe across all platforms. Odds are that -className
is declared as a simple wrapper around NSStringFromClass()
anyway...