Может ли метод класса NSNumber различать int со знаком и без знака? - PullRequest
1 голос
/ 28 апреля 2011

Есть ли способ проверить NSNumber, чтобы определить, является ли оно int или unsigned int.Я пытался сделать это с помощью objCType, но я не могу сказать разницу.Рассмотрим следующий сценарий:

NSNumber *number1 = [NSNumber numberWithUnsignedInt:100];
NSNumber *number2 = [NSNumber numberWithInt:100];

NSLog(@"%@",[NSString stringWithUTF8String:[number1 objCType]]);
NSLog(@"%@",[NSString stringWithUTF8String:[number2 objCType]]);

Вывод: i i

Кто-нибудь знает, как решить эту проблему?

Ответы [ 5 ]

2 голосов
/ 28 апреля 2011

objCType не гарантирует, что возвращаемый тип будет таким же, как тип, который вы указали.

То, что вы пытаетесь сделать, по существу игнорирует точку NSNumber, то естьчтобы избежать неуклюжести, с которой необходимо обрабатывать числовые значения в C. Оборачивая числовое значение в NSNumber, вы можете сравнить его с любым другим таким значением без учета их «фактических» (побитовых) типов, ивы можете получить значение обратно в другом «фактическом» типе, чем вы начали. *

Он не возвращает вам точно такой же тип, потому что ему не нужно - вы кладете все, что выхочешь и забирай что хочешь.Во всяком случае, тип переменной C неизвестен.

Я полагаю, вам нужно использовать NSNumber, потому что вам нужно вставить числовые значения в коллекцию Какао?Возможно, вам придется обернуть NSNumber в свой собственный объект, который также ведет запись начального типа.Для этого потребуется длинный switch или куча if / else s ...


* Единственное предостережение здесь заключается в том, что теперь вы должны быть снова обеспокоеныразмер типа: попытка поместить значение, большее FLT_MAX в float, например, дает вам мусор.

2 голосов
/ 28 апреля 2011

Нет. Под капотом NSNumber используется CFNumber, и последний не хранит значения без знака - методы NSNumber проверяют переданное значение и, если оно слишком велико, чтобы поместиться в тип со знаком того же размера, оно использует следующий больший знак тип. (И да, если вы храните большое беззнаковое 64-битное целое число NSNumber использует внутреннее 128-битное целое число со знаком.)

Если вы хотите отслеживать исходный тип, вам придется сделать это самостоятельно, например, создать объект с полем для типа и полем для числа ...

2 голосов
/ 28 апреля 2011

Почему это проблема?

NSNumber, проще говоря, не заботится о том, является ли число неподписанным или подписанным, и будет приводить или преобразовывать по мере необходимости;точно так же, как все равно, является ли число фиксированным или с плавающей запятой.

Тип числа действительно имеет значение только при создании.

1 голос
/ 28 апреля 2011

Вы можете расширить NSNumber, используя категорию.

@implements NSNumber (Signed)
    - (BOOL)isNumberSigned {
        // Test if number less than zero
        // return the result
    }

В этом красота Objective-C;очень просто продлить класс.

0 голосов
/ 25 марта 2012

Использование [- doubleValue], [- stringValue] или [- decimalValue] может показать, было ли исходное значение отрицательным при создании с использованием подписанного метода init. Я удивлен, что нет простой - wasCreatedSigned функциональности.

BOOL negTest;
negTest = ([myNSNumber doubleValue] < 0);                 // <0.1 micro sec
negTest = [[myNSNumber stringValue] hasPrefix:@"-"];      // >1.5 micro sec
negTest = ([myNSNumber decimalValue]._isNegative);        // >2.5 micro sec
negTest = ([myNSDecimalNumber decimalValue]._isNegative); // <0.1 micro sec

Внутренне NSNumber IS знает о подписанном состоянии его значения.

Что касается -objCType Я заметил, что это не всегда отражает тип init, как сказано в документации. Но он будет точно отличать числа с плавающей запятой (double) (d) от целых чисел (c, s, i, q, Q ...).

Вот код, с которым можно поиграть, он покажет некоторые странности (проверено на iOS 4.3):

void isNeg(NSNumber* num, NSString* initMethod);
void isNeg(NSNumber* num, NSString* initMethod)
{
    printf("\r");
    NSLog(@"%@ (class:%@)", initMethod, [num class]);

    double dval = [num doubleValue];
    NSLog(@"Is Negative:%c, objCType:%s", (dval<0)?'Y':'N', [num objCType]);
    NSLog(@"strVal: %@", [num stringValue]);
    NSLog(@"%%f    : %f", dval);
    NSLog(@"%%g    : %g", dval);
    NSLog(@"%%lld  : %lld", [num longLongValue]);
    NSLog(@"%%llu  : %llu", [num unsignedLongLongValue]);
}

// main...
double testDouble = 10001e-9;
Class nc = [NSNumber class];

isNeg([nc numberWithChar:    -1], @"Char");
isNeg([nc numberWithChar:    -2], @"Char");
isNeg([nc numberWithChar:    -3], @"Char");
isNeg([nc numberWithChar:     1], @"Char");
isNeg([nc numberWithChar:    12], @"Char");
isNeg([nc numberWithChar:    13], @"Char");
isNeg([nc numberWithUnsignedChar: 12], @"UChar");
isNeg([nc numberWithUnsignedChar: 13], @"UChar");

isNeg([nc numberWithLongLong:        -LONG_LONG_MAX], @"LongLong");
isNeg([nc numberWithLongLong:         LONG_LONG_MAX], @"LongLong");
isNeg([nc numberWithUnsignedLongLong: ULONG_LONG_MAX], @"ULongLong");

isNeg([nc numberWithDouble:-LONG_LONG_MAX], @"Double");
isNeg([nc numberWithDouble: ULONG_LONG_MAX], @"Double");

isNeg([nc numberWithDouble:-testDouble], @"Double");
isNeg([nc numberWithDouble: testDouble], @"Double");

nc = [NSDecimalNumber class];
isNeg([nc numberWithDouble:-testDouble], @"Double");
isNeg([nc numberWithDouble: testDouble], @"Double");
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...