Проверьте, нет ли NSNumber
Как проверить, является ли объект NSNumber нулевым или пустым?
OK nil легко:
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
было установлено равным nil?
[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
. Таким образом, оно содержит произвольное число?
Ответы
Ответ 1
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
не имеет понятия "пустой" . Cocoa уже имеет 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;
// ...
}
Теперь этот параметр позволяет различать "пустой" , "не пустой" и "не в контейнере" (например, незаконный ключ).
Ответ 2
NSNumber
является либо nil
, либо содержит число, между которыми нет ничего. "Пустота" - это понятие, которое зависит от семантики конкретного объекта, и поэтому нет смысла искать общую проверку пустоты.
Что касается ваших примеров, происходит несколько вещей:
NSMutableDictionary *hash = [NSMutableDictionary dictionary];
[hash setObject:@"" forKey:@"key"];
NSNumber *number = [hash objectForKey:@"key"];
NSLog(@"%i", [number intValue]);
NSLog
будет печатать 0
здесь, но только потому, что метод a intValue
в NSString
. Если вы измените сообщение на то, что может выполнить только 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])
Надеюсь, что это поможет.
Ответ 3
NSNumber
являются неизменяемыми и могут быть созданы только с помощью метода factory или исходного метода, который дает им некоторое числовое значение. Насколько я знаю, невозможно получить "пустой" NSNumber, если вы не подсчитаете 0.
Ответ 4
Очень часто (по крайней мере, для меня), чтобы получить объект из словаря, ожидайте, что он будет NSNumber, а затем вернет объект nil. Если это произойдет, и вы сделаете 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]];
Ответ 5
Работа с Swift 2.0 и Parse:
var myNumber = yourArray!.objectForKey("yourColumnTitle")
if (myNumber == nil) {
myNumber = 0
}
В моем случае мне тогда пришлось:
let myNumberIntValue = myNumber!.intValue