Подтвердить что ты не робот

Получить тип 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.

4b9b3361

Ответ 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 }