2010-09-15 31 views
18

¿Cómo verifico si un objeto NSNumber es nulo o está vacío?compruebe si NSNumber está vacío

OK nula es fácil:

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

Pero si el objeto ha sido creado, pero no hay ningún valor en ella porque una misión fracasó, ¿cómo puedo comprobar esto? Usa algo como esto?

if ([myNumber intValue]==0) 
    doSomething 

¿Hay un método general para el ensayo de los objetos en el vacío como por NSString disponibles (ver este post)?

Ejemplo 1

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

Qué valor no contienen emptyNumber? ¿Cómo puedo verificar si emptyNumber está vacío?

Ejemplo 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; 

¿Qué pasa si uso esto después de emptyNumber se fijó a cero?

[emptyNumber intValue] 

¿Obtengo cero?

Ejemplo 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!"); 

gusta esta manera NSLog nunca es llamado. myEmptyValue no es nil y no NSNull. ¿Entonces contiene un número arbitrario?

+0

@ [0.7] le daré una NSNumber que definitivamente no es cero, pero intValue devolverá 0. Entonces esa es una mala prueba. – gnasher729

+0

Upvoted por el gran detalle que ayudó a explicar algo que estoy tratando de los valores predeterminados. NSNumber * savedPin = [[NSUserDefaults standardUserDefaults] valueForKey: @ "someKey"]; devuelve un objeto que tiene la clase __NSCFConstantString y, por lo tanto, las comparaciones con cero fallaron. ¡GRACIAS! –

Respuesta

12

NSValue, NSNumber, ... se supone que se crean a partir de un valor y siempre tienen uno. La prueba de un valor específico como 0 solo funciona si no está en el rango de valores válidos con los que está trabajando.

En el caso improbable de que el código es más recta hacia adelante para trabajar con si usted tiene un valor que representa "no válido" o"no ajustada" y no se puede utilizar nil (por ejemplo, con los contenedores estándar) puedes usar NSNull en su lugar.

En su primer ejemplo esto podría ser:

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

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

Pero tenga en cuenta que simplemente no se puede insertar (o eliminar) ese valor a menos que necesite para diferenciar nil (es decir, no en el contenedor) y, decir, "no válido":

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

en cuanto al segundo ejemplo, -intValue dar s usted 0 - pero simplemente porque el envío de mensajes a nil devuelve 0. También puede obtener 0 p. para un NSNumber cuyo intValue se configuró en 0 antes, lo que podría ser un valor válido.
Como ya he escrito anteriormente, solo puede hacer algo como esto si 0no es un valor válido para usted. Tenga en cuenta el para usted, lo que funciona mejor depende completamente de cuáles son sus requisitos.

Vamos a tratar de resumir :

Opción # 1:

Si usted no necesita todos los valores de la gama de números, se podría utilizar una (o 0-1 o .. .) y -intValue/... para representar específicamente "vacío". Aparentemente este no es el caso para ti.

Opción # 2:

Simplemente no almacenar o eliminar los valores del contenedor si son "vacío":

// 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 
} 

Sin embargo, esto significa que no hay diferencia entre llaves que están vacías y llaves que nunca existen o son ilegales.

Opción # 3:

En algunos casos raros es más conveniente para mantener todas las claves en el diccionario y representan "vacío" con un valor diferente. Si no puede usar uno del rango numérico, tenemos que poner algo diferente ya que NSNumber no tiene un concepto de "vacío". El cacao ya tiene NSNull para estos casos:

// 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; 
    // ... 
} 

Esta opción ahora le permite diferenciar entre "vacío", "no está vacío" y "no en el contenedor" (clave, por ejemplo, ilegal).

+0

Edité mi publicación. ¿Cómo puedo probar el vacío en este "caso especial"? ¿Está en el rango de valores válidos aquí? – testing

+0

Está insertando '[NSNull null]' para probar más tarde un objeto NSNumber en vacío. OK, pero ¿qué son los contenedores estándar? No puedo garantizar qué valor se asigna a mi objeto NSNumber. Así que no sé cuándo insertar 'nil' o' NSNull'. En mi ejemplo, también podría ser una cadena vacía.¿Debería probar primero el valor de retorno de 'objectForKey' si es una cadena vacía y luego debería insertar' nil' o 'NSNull' en mi objeto NSNumber? Creo que siempre debería insertar nil, a menos que necesite NSNull para algún caso. Ver mi segundo ejemplo. – testing

+1

@testing: los contenedores estándar son los de Cocoa Touch ('NSArray',' NSDictionary', ...). Las primeras pruebas de muestra para el objeto son 'NSNull', el segundo asume * que no se pone el valor en el contenedor * - no se puede insertar' nil' en esas, 'nil' representa *" no en el contenedor " *. Simplemente tiene que decidir si tiene que diferenciar entre * "inválido" */* "no existente" * y * "que no está en el contenedor" *. Tu última oración está cerca de lo que digo, o no la pongas en el contenedor (así que obtienes 'nil' para' -objectForKey: ... ') o vas con' NSNull'. –

3

NSNumber es nil, o que contiene un número, nada en el medio. "Vacío" es una noción que depende de la semántica del objeto particular y, por lo tanto, no tiene sentido buscar una verificación de vacío general.

En cuanto a los ejemplos, hay varias cosas que suceden:

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

El NSLog imprimirá 0 aquí, pero sólo porque no hay un método intValue en NSString. Si cambia el mensaje a algo que sólo NSNumber puede hacer, el código fallará:

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

Esto lanzará:

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

que significa que son no conseguir algún valor general de “vacío” de vuelta del hash, acaba de obtener el NSString que almacenó allí.

Cuando tiene un NSNumber vacío y lo envía un mensaje, el resultado será cero.Eso es simplemente una convención lenguaje que simplifica código:

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

se convertirá en esto:

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

Espero que esto ayude.

+0

Entonces, ¿qué hace NSNumber * test = [NSNull null]? –

+1

Tal como está escrito, ese código no tiene mucho sentido. NSNull es solo una "versión de objeto del valor nulo" y la única razón por la que existe es para representar un valor "vacío" en colecciones que no pueden almacenar nil directamente. – zoul

+0

Gracias, sí, supongo que estoy tratando de tener claro en mi mente exactamente el rango de posibilidades que necesito considerar para NSNumber –

0

NSNumber s son inmutables y solo se pueden crear con un método de fábrica o un método inicial que les dé algún valor numérico. Por lo que yo sé, no es posible terminar con un NSNumber 'vacío', a menos que cuente 0.

0

Es muy común (al menos para mí) sacar un objeto del diccionario, esperar que vaya ser un NSNumber y luego hacer que devuelva un objeto nil. Si esto sucede y haces un intValue, se bloqueará.

Lo que hago es configurar la protección nula porque prefiero obtener un valor predeterminado que un bloqueo.

Una forma es:

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

Y tengo uno igual para los flotadores. Entonces al menos obtienes tu valor predeterminado. Otra forma es simplemente crear un método para la protección nula ..

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

Que uno que se dice así:

NSNumber *value = [self nilProtectionForNumber:[dict objectForKey:keyThatShouldBeNSNumber] withDefault:[NSNumber numberWithInt:0]]; 
0

Tratar con Swift 2.0 y Parse:

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

En mi caso, tuve que:

let myNumberIntValue = myNumber!.intValue 
Cuestiones relacionadas