Получить тип 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.
Ответы
Ответ 1
Я рекомендую использовать метод -[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.
Ответ 2
Вы можете получить тип таким образом, не требуется никаких сравнений строк:
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;
Ответ 3
Если вы хотите различать логические значения и все остальное, вы можете использовать тот факт, что логические NSNumbers всегда возвращают общий экземпляр:
NSNumber *num = ...;
if (num == (void*)kCFBooleanFalse || num == (void*)kCFBooleanTrue) {
// num is boolean
} else {
// num is not boolean
}
Ответ 4
NSNumber явно не гарантирует, что возвращаемый тип будет соответствовать методу, используемому для его создания, поэтому сделать это вообще, вероятно, плохая идея.
Однако, возможно, вы могли бы сделать что-то подобное (вы также можете сравнить с objc_getClass("NSCFNumber")
и т.д., но это, возможно, более портативно):
Class boolClass = [[NSNumber numberWithBool:YES] class];
/* ... */
if([myNum isKindOfClass:boolClass]) {
/* ... */
}
Ответ 5
Причина, по которой компилятор предупреждает вас, и это не работает, потому что -[NSObject className]
объявлен в категории в NSObject в Mac OS X (в NSScriptClassDescription.h) и не объявлен на iPhone. (Очевидно, он не поддерживает AppleScript.) NSStringFromClass([myNum class])
- это то, что вы должны использовать для обеспечения безопасности на всех платформах. Коэффициенты заключаются в том, что -className
объявляется как простая оболочка вокруг NSStringFromClass()
в любом случае...
Ответ 6
Используйте метод -[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, то этот метод, вероятно, не должен использоваться в узком цикле.
Ответ 7
В 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
}
Ответ 8
NSString *classString = NSStringFromClass([myNum class]);
Это должно соответствовать нужной строке.
Ответ 9
Чтобы проверить, что NSNumber содержит значение bool, попробуйте следующее:
if (strcmp([myNumber objCType], [@(YES) objCType]) == 0)
NSLog(@"%@", [myNumber boolValue] ? @"true" : @"false");
Ответ 10
Документация objCType
гласит, что The returned type does not necessarily match the method the number object was created with
Во-вторых, другие методы сравнения класса числа с данным типом класса или предположения о том, что экземпляры булевого числа, являющиеся общими одноточиями, не документированы.
Более (не полностью) надежный способ заключается в том, чтобы зависеть от NSJSONSerialisation, поскольку он правильно распознает числовые экземпляры, созданные с помощью bool, и выводит true/false в json. Это то, о чем мы можем ожидать, что 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"];
}
Ответ 11
объект проверки имеет тип NSNumber:
if([obj isKindOfClass:NSClassFromString(@"__NSCFNumber")])
{
//NSNumber
}