проверить, если NSNumber пуст - PullRequest
       5

проверить, если NSNumber пуст

18 голосов
/ 15 сентября 2010

Как проверить, является ли объект NSNumber нулевым или пустым?

ОК, нет, просто:

NSNumber *myNumber;
if (myNumber == nil)
    doSomething

Но если объект был создан, но в нем нет значения из-за неудачного назначения, как я могу проверить это? Использовать что-то вроде этого?

if ([myNumber intValue]==0)
   doSomething

Существует ли общий метод проверки объектов на пустоту, например, для NSString (см. post )?

Пример 1

NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
[dict setValue:@"" forKey:@"emptyValue"];
NSNumber *emptyNumber = [dict objectForKey:@"emptyValue"];

Какое значение содержит emptyNumber? Как я могу проверить, является ли emptyNumber пустым?

Пример 2

NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
[dict setValue:@"" forKey:@"emptyValue"];
NSString *myString = [dict objectForKey:@"emptyValue"];
if (myString == nil || [myString length] == 0)
    // got an empty value
    NSNumber *emptyNumber=nil;

Что произойдет, если я использую это после того, как emptyNumber был установлен в ноль?

[emptyNumber intValue]

Получу ли я ноль?

Пример 3

NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
[dict setValue:@"" forKey:@"emptyValue"];
NSNumber *myEmptyValue = [dict objectForKey:@"emptyValue"];
if (myEmptyValue == nil)
    // NSLog is never called
    NSLog(@"It is empty!");

Таким образом, NSLog никогда не вызывается. myEmptyValue не nil и не NSNull. Значит, оно содержит произвольное число?

Ответы [ 5 ]

12 голосов
/ 15 сентября 2010

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

В редком случае, когда код более прост для работы, если у вас есть значение, которое представляет «неверно» или «не установлено» и вы не можете использовать nil (например, со стандартными контейнерами) вместо него можно использовать NSNull.

В вашем первом примере это может быть:

[dict setValue:[NSNull null] forKey:@"emptyValue"];

if ([dict objectForKey:@"emptyValue"] == [NSNull null]) {
    // ...
}

Но учтите, что вы можете просто не вставлять (или удалять) это значение, если вам не нужно различать nil (то есть не в контейнере) и, скажем, "неверно" :

if ([dict objectForKey:@"nonExistent"] == nil) {
    // ...
}

Что касается второго примера , -intValue дает вам 0 - но просто потому, что отправка сообщений на nil возвращает 0. Вы также можете получить 0 например для NSNumber, для которого intValue ранее было установлено 0, что может быть допустимым значением.
Как я уже писал выше, вы можете сделать что-то подобное, только если 0 не является допустимым значением для вас . Обратите внимание на для вас , то, что работает лучше всего, полностью зависит от ваших требований.

Позвольте мне попытаться обобщить :

Вариант № 1:

Если вам не нужны все значения из диапазона чисел, вы можете использовать одно (0 или -1 или ...) и -intValue / ..., чтобы специально представлять «пусто» . Это, очевидно, не так для вас.

Вариант № 2:

Вы просто не сохраняете и не удаляете значения из контейнера, если они "пустые" :

// add if not empty:
[dict setObject:someNumber forKey:someKey];    
// remove if empty:
[dict removeObjectForKey:someKey];
// retrieve number:
NSNumber *num = [dict objectForKey:someKey];
if (num == nil) {
    // ... wasn't in dictionary, which represents empty
} else {
    // ... not empty
}

Однако это означает, что нет никакой разницы между пустыми ключами и ключами, которые никогда не существуют или являются незаконными.

Вариант № 3:

В некоторых редких случаях удобнее хранить все ключи в словаре и представлять «пусто» с другим значением. Если вы не можете использовать один из диапазона номеров, мы должны ввести что-то по-другому, так как NSNumber не имеет понятия «пусто» . Какао уже имеет NSNull для таких случаев:

// set to number if not empty:
[dict setObject:someNumber forKey:someKey];
// set to NSNull if empty:
[dict setObject:[NSNull null] forKey:someKey];
// retrieve number:
id obj = [dict objectForKey:someKey];
if (obj == [NSNumber null]) {
    // ... empty
} else { 
    // ... not empty
    NSNumber *num = obj;
    // ...
}

Этот параметр теперь позволяет различать «пусто» , «не пусто» и «не в контейнере» (например, недопустимый ключ).

3 голосов
/ 15 сентября 2010

NSNumber либо nil, либо содержит число, ничего между ними. «Пустота» - это понятие, которое зависит от семантики конкретного объекта, и поэтому нет смысла искать общую проверку пустоты.

Что касается ваших примеров, происходит несколько вещей:

NSMutableDictionary *hash = [NSMutableDictionary dictionary];
[hash setObject:@"" forKey:@"key"];
NSNumber *number = [hash objectForKey:@"key"];
NSLog(@"%i", [number intValue]);

NSLog будет печатать 0 здесь, но только потому, что в NSString есть метод intValue. Если вы измените сообщение на то, что может сделать только NSNumber, код потерпит неудачу:

NSLog(@"%i", [number unsignedIntValue]);

Это бросит:

-[NSCFString unsignedIntValue]: unrecognized selector sent to instance 0x303c

Это означает, что вы не получаете какое-то общее «пустое» значение из хеша, вы просто получаете NSString, который вы там хранили.

Если у вас есть пустое (== nil) NSNumber и отправлено ему сообщение, результат будет нулевым. Это просто соглашение о языке, упрощающее код:

 (array != nil && [array count] == 0)
 (someNumber == nil ? 0 : [someNumber intValue])

превратится в это:

 ([array count] == 0)
 ([someNumber intValue])

Надеюсь, это поможет.

0 голосов
/ 09 декабря 2015

Работа со Swift 2.0 и Parse:

var myNumber = yourArray!.objectForKey("yourColumnTitle")
    if (myNumber == nil) {
    myNumber = 0
      }

В моем случае мне пришлось:

    let myNumberIntValue = myNumber!.intValue
0 голосов
/ 21 июня 2012

Очень распространено (по крайней мере для меня), чтобы вытащить объект из словаря, ожидать, что это будет NSNumber, а затем вернуть ему нулевой объект.Если это произойдет, и вы сделаете intValue, это приведет к сбою.

Что я делаю, так это настройку защиты nil, потому что я предпочел бы получить значение по умолчанию, чем сбой.

Один из способов:

-(int) intForDictionary:(NSDictionary *)thisDict objectForKey: (NSString *)thisKey withDefault: (int)defaultValue
{
    NSNumber *thisNumber = [thisDict objectForKey:thisKey];
    if (thisNumber == nil) {
        return defaultValue;
    }
    return [thisNumber intValue];
}

И у меня есть такой же, как и для поплавков.Тогда вы по крайней мере получите значение по умолчанию.Другой способ - просто создать метод для нулевой защиты.

-(NSNumber *)nilProtectionForNumber: (NSNumber *)thisNumber withDefault: (NSNumber *)defaultNumber
{
    if (thisNumber) {
        return thisNumber;
    }
    else
        return defaultNumber;
}

Тот, который вы бы назвали так:

NSNumber *value = [self nilProtectionForNumber:[dict objectForKey:keyThatShouldBeNSNumber] withDefault:[NSNumber numberWithInt:0]];
0 голосов
/ 15 сентября 2010

NSNumber s являются неизменными и могут быть созданы только с помощью заводского метода или начального метода, который дает им некоторое числовое значение.Насколько я знаю, невозможно получить «пустой» NSNumber, если не считать 0.

...