¿Cuál es la forma correcta de verificar una cadena nula en Objective-C?

184

Estaba usando esto en mi aplicación de iPhone

if (title == nil) {
    // do something
}

pero arroja alguna excepción, y la consola muestra que el título es "(nulo)".

Entonces estoy usando esto ahora:

if (title == nil || [title isKindOfClass:[NSNull class]]) {
    //do something
}

¿Cuál es la diferencia y cuál es la mejor manera de determinar si una cadena es nula?

Teo Choong Ping
fuente
Solución: jayprakashdubey.blogspot.in/2014/09/…
Jayprakash Dubey

Respuestas:

395

Como otros han señalado, hay muchos tipos de "nulo" en Cocoa / Objective C. Pero otra cosa a tener en cuenta es que [title isKindOfClass: [NSNull class]] es inútilmente complejo ya que [NSNull null] está documentado como un singleton para que pueda verificar la igualdad del puntero. Vea Temas para el cacao: uso de nulo .

Entonces, una buena prueba podría ser:

if (title == (id)[NSNull null] || title.length == 0 ) title = @"Something";

Observe cómo puede usar el hecho de que incluso si el título es nulo, title.length devolverá 0 / nil / false, es decir, 0 en este caso, por lo que no tiene que ponerlo en mayúsculas o minúsculas. Esto es algo a lo que las personas que son nuevas en Objective C tienen problemas para acostumbrarse, especialmente cuando vienen de otros lenguajes donde los mensajes / llamadas a métodos fallan.

Peter N Lewis
fuente
¡Gracias! Sin embargo, hice esta pregunta en primer lugar porque recibía una excepción porque el "título" era nulo.
Teo Choong Ping
1
¿De qué tipo se supone que es el título? Si se trata de un NSString, por ejemplo, recibo la siguiente advertencia: la comparación de los distintos tipos de Objective-C 'struct NSNull *' y 'struct NSString *' carece de un reparto ¿Hay alguna forma de eliminar esto (no sé si las cosas han cambiado desde entonces esta pregunta fue hecha)
thebossman
1
Me sirve para publicar código sin compilarlo ;-). El título es presumiblemente un NSString, pero independientemente del tipo de título, simplemente convierte nulo en el tipo de identificación genérico: (id) [NSNull null].
Peter N Lewis, el
1
@JLT nil y [NSNull null] nunca serán lo mismo. [NSNull null] es un objeto singleton que puede usarse como un sustituto de nil cuando nil no puede usarse (por ejemplo, en un valor NSArray o NSDictionary). Por lo tanto, un caso de uso podría ser donde tenía una NSArray de cadenas opcionales, algunas de las cuales podrían ser nulas, y usa [NSNull null] en la matriz para los casos nulos. En la práctica, la prueba rara vez se necesita, solo cuando usted (o una biblioteca que usa) usa activamente [NSNull null] como marcador de posición.
Peter N Lewis
1
Venir aquí flameo, y en busca de la razón por la cual un Mapvalor de punto - que es nullen Dart - no se corresponde con nilo NULLen Objective C. La razón era que en realidad NUNull nullno es así, la NULLnula. ¡Gracias @PeterNLewis!
Aleksandar
25

es tan simple como

if([object length] >0)
{
  // do something
}

recuerde que en el objetivo C si el objeto es nulo, devuelve 0 como valor.

Esto te dará una cadena nula y una cadena de longitud 0.

Bluephlame
fuente
49
Esto no funcionará si el objeto es NSNull, aún debe comprobarlo explícitamente primero.
Jeremy Mack
66
también puede hacer una categoría para NSNull para que devuelva 0 al mensaje de longitud :)
Mihai Timar
1
Sí, esto se bloqueará si el objeto es NSNull.
Mike Gledhill
Esto se bloqueará si el objeto es igual a NSNull
Joan
1
Además del problema del selector NSNull no reconocido, esto no diferenciará entre un puntero NSString que sea nulo o un NSString que esté realmente allí pero que sea esencialmente una cadena vacía. (Por ejemplo, como literal object = @"";o object = nil;)
KellyTheDude
6

Consulte los siguientes artículos relacionados en este sitio:

Creo que su error está relacionado con algo más, ya que no debería necesitar hacer una verificación adicional.

Consulte también esta pregunta relacionada: Comprobación adecuada de la columna de texto sqlite nula

TimM
fuente
Molesto, no tengo suficientes "puntos" para agregar un segundo hipervínculo (incluso a algo en este sitio) ver también: - stackoverflow.com/questions/598396/…
TimM
...me permitirá. Aunque usted debe ser capaz de editar sus propios mensajes de representante 0.
Rog
Gracias, eso fue muy amable. Cuando escribí mi publicación inicial, decía que los nuevos usuarios solo pueden agregar 1 hipervínculo (lo que parece un poco duro, especialmente para los enlaces cruzados en este sitio).
TimM
6

He descubierto que para hacerlo realmente bien, tienes que hacer algo similar a

if ( ( ![myString isEqual:[NSNull null]] ) && ( [myString length] != 0 ) ) {
}

De lo contrario, obtendrá situaciones extrañas en las que el control seguirá pasando por alto su cheque. No he encontrado uno que supere los isEqualcontroles de longitud.

Guardius
fuente
5

¿Qué pasa con todos estos "funciona para mí respuestas"? Todos estamos codificando en el mismo idioma y las reglas son

  1. Asegúrese de que la referencia no sea nula
  2. Verifique y asegúrese de que la longitud de la cadena no sea 0

Eso es lo que funcionará para todos. Si una solución determinada solo "funciona para usted", es solo porque el flujo de su aplicación no permitirá un escenario en el que la referencia puede ser nula o la longitud de la cadena sea 0. La forma correcta de hacerlo es el método que manejará lo que quieres en todos los casos.

nenchev
fuente
44
Si la referencia es nil(nota: no "nula"), enviar un mensaje, como length, producirá 0 (o el valor 0 apropiado para el tipo de retorno del método). Esa es la regla del lenguaje. No hay necesidad de verificar por nilseparado en este caso.
jscs
Dije nulo simplemente debido a los hábitos de C ++, y si su código está llamando a métodos en objetos nulos, es probable que su código esté roto. Encontrará que los métodos de llamada en NULL / NIL (mismo concepto) generalmente son una mala idea en cualquier idioma. El hecho de que obj-c te permita hacer algo así no significa que debas pasar objetos nulos e intentar usarlos sin preocuparte.
nenchev
1
Enviar longitud a cero produce 0 - PERO enviar longitud a NSNull produce una excepción.
cdstamper
@nenchev Nadie dice nada acerca de simplemente pasar objetos nulos, pero verificar nil, luego llamar a un método y usar su valor de retorno es IMO peor que usar una función de lenguaje como está destinado a usarse y verificar la validez del valor de retorno del método después.
Kevin
@Kevin No estoy seguro de cómo es peor, solo porque es una función de lenguaje no significa que sea genial. No verificar si su nulo podría abrir una ruta de código que podría conducir a un error de tiempo de ejecución más difícil de rastrear. Por lo general, es mejor verificar que sus entradas sean las esperadas y reaccionar en consecuencia si no lo son. Personalmente, no me gusta la "característica" de no obtener excepciones de tiempo de ejecución cuando intento enviar un mensaje a un objeto nulo, ya que a menudo hace que sea más fácil pasar por alto algunos errores de tiempo de ejecución.
nenchev
4

Si desea probar contra todos los objetos nulos / vacíos (como cadenas vacías o conjuntos / conjuntos vacíos) puede usar lo siguiente:

static inline BOOL IsEmpty(id object) {
    return object == nil
        || ([object respondsToSelector:@selector(length)]
        && [(NSData *) object length] == 0)
        || ([object respondsToSelector:@selector(count)]
        && [(NSArray *) object count] == 0);
}
diederikh
fuente
2
En realidad, esto no verifica el objeto == [NSNull null] que probablemente tendría sentido.
Peter N Lewis
3

Hay dos situaciones:

Es posible que un objeto sea [NSNull null], o es imposible.
Por lo general, su aplicación no debería usarlo [NSNull null];, solo debe usarlo si desea colocar un objeto " nulo " en una matriz, o usarlo como un valor de diccionario. Y luego debe saber qué matrices o diccionarios pueden contener valores nulos y cuáles no.
Si cree que una matriz nunca contiene [NSNull null]valores, no la verifique. Si hay una [NSNull null], puede obtener una excepción, pero está bien: las excepciones de Objective-C indican errores de programación. Y tiene un error de programación que debe corregirse cambiando algún código.

Si un objeto puede ser [NSNull null], entonces verifica esto simplemente mediante pruebas
(object == [NSNull null]). Llamar isEqualo verificar la clase del objeto no tiene sentido. Solo hay un [NSNull null]objeto, y el antiguo operador de C lo comprueba bien de la manera más directa y eficiente.

Si marca un NSStringobjeto que no puede ser [NSNull null](porque sabe que no puede ser [NSNull null]o porque acaba de verificar que es diferente de [NSNull null], entonces debe preguntarse cómo desea tratar una cadena vacía, que es una con longitud 0. Si usted tratar es como una nullcadena nil, luego test (object.length == 0). object.length devolverá 0 si object == nil, por lo que esta prueba cubre objetos nulos y cadenas con longitud 0. Si trata una cadena de longitud 0 diferente de una cadena nula, simplemente verifique si object == nil.

Finalmente, si desea agregar una cadena a una matriz o un diccionario, y la cadena podría ser nula, tiene la opción de no agregarla, reemplazarla @""o reemplazarla por [NSNull null]. Reemplazarlo @""significa que pierde la capacidad de distinguir entre "sin cadena" y "cadena de longitud 0". Reemplazarlo [NSNull null]significa que debe escribir código cuando accede a la matriz o diccionario que busca [NSNull null]objetos.

gnasher729
fuente
Muy largo, pero esto es bueno. ¡NSNull SOLO APARECE EN SINGLETONS! Toda esta pregunta no tiene sentido, me dice que el codificador no estaba haciendo algo correcto, y muchos más en el futuro también, no leyó el manual / buena práctica de código
Stephen J
2

Solo verifica si es nulo

if(data[@"Bonds"]==nil){
  NSLog(@"it is nil");
}

o

if ([data[@"Bonds"] isKindOfClass:[NSNull class]]) {
    NSLog(@"it is null");
}
Gami Nilesh
fuente
2

Solución MACRO (2020)

Aquí está la macro que uso para una cadena segura en lugar de obtener una cadena " (nula) " en un UILabel, por ejemplo:

#define SafeString(STRING) ([STRING length] == 0 ? @"" : STRING)

supongamos que tiene una clase de miembro y una propiedad de nombre, y el nombre es nulo:

NSLog(@"%@", member.name); // prints (null) on UILabel

con macro:

NSLog(@"%@", SafeString(member.name)); // prints empty string on UILabel

agradable y limpio 😊

Solución de extensión (2020)

Si prefiere marcar una cadena nula y vacía en su proyecto, puede usar mi línea de extensión a continuación:

NSString + Extension.h

///
/// Checks if giving String is an empty string or a nil object or a Null.
/// @param string string value to check.
///
+ (BOOL)isNullOrEmpty:(NSString*)string;

NSString + Extension.m

+ (BOOL)isNullOrEmpty:(NSString*)string {
    if (string) { // is not Nil
        NSRange range = [string rangeOfString:string];
        BOOL isEmpty = (range.length <= 0 || [string isEqualToString:@" "]);
        BOOL isNull = string == (id)[NSNull null];

        return (isNull || isEmpty);
    }

    return YES;
}

Ejemplo de uso

if (![NSString isNullOrEmpty:someTitle]) {
    // You can safely use on a Label or even add in an Array for example. Remember: Arrays don't like the nil values!
}
mgyky
fuente
1
if(textfield.text.length == 0){
   //do your desired work
}
Muhammad Aamir Ali
fuente
1

Prueba esto para comprobar nulo

 if (text == nil)
Vineesh TP
fuente
1
@interface NSString (StringFunctions)
- (BOOL) hasCharacters;
@end

@implementation NSString (StringFunctions)
- (BOOL) hasCharacters {
    if(self == (id)[NSNull null]) {
        return NO;
    }else {
        if([self length] == 0) {
            return NO;
        }
    }
    return YES;
}
@end

NSString *strOne = nil;
if([strOne hasCharacters]) {
    NSLog(@"%@",strOne);
}else {
    NSLog(@"String is Empty");
}

Esto funcionaría con los siguientes casos, NSString *strOne = @""OR NSString *strOne = @"StackOverflow"OR NSString *strOne = [NSNull null]OR NSString *strOne.

Hemang
fuente
0

Si ese tipo de cosas aún no existe, puede crear una categoría NSString:

@interface NSString (TrucBiduleChoseAdditions)

- (BOOL)isEmpty;

@end

@implementation NSString (TrucBiduleChoseAdditions)

- (BOOL)isEmpty {
    return self == nil || [@"" isEqualToString:self];
}

@end
Rémy
fuente
Probablemente sea exagerado y no creo que resuelva este problema.
Rog
9
El self == nil no tiene sentido: si self fue nil, el Objetivo C no te habría llamado en primer lugar. [(NSString *) nil isEmpty] simplemente devolvería 0 / nil / false sin llamar a su código.
Peter N Lewis
44
En realidad, además de eso, [(NSString *) nil isEmpty] devolverá falso. Cuando se escriben dichos métodos del Objetivo C, es mejor definirlos de modo que 0 / nil / false sea nulo, por lo que sería mejor escribir el método como hasCharacters. Tenga en cuenta que la longitud ya funciona para esto, ya que puede usar if (s.length) en cualquier lugar que desee usar if (! S.isEmpty) y s.length devolverá 0 correctamente para el caso s == nil.
Peter N Lewis
Este es un accidente grave. Implementó "isEmpty" para NSString, pero si en realidad es NSNull, entonces isEmpty se enviará a NSNull y se bloqueará porque no responde a ese mensaje.
daniel.gindi
0

Lo que funciona para mi es if ( !myobject )

Joseph Bolade Caxton-Idowu
fuente
3
Eso no funciona para objetos nulos, solo para objetos nulos. Por ejemplo ... NSArray *testarray = [NSArray arrayWithObjects:[NSNull null],@"", nil]; NSString *string = [testarray objectAtIndex:0]; NSLog(@"null string value: %@",string); if (!string) { NSLog(@"string evaluates to null"); } if (string && (string==(id)[NSNull null])) { NSLog(@"string does not evaluate to null"); }
Rik Smith-Unna
Err ... perdón por el formato, pero el código se compilará :)
Rik Smith-Unna
0

La comprobación completa de una cadena para condiciones nulas puede ser la siguiente: <\ br>

    if (mystring)
     {
       if ([mystring isEqualToString: @ ""])
        {
          mystring = @ "alguna cadena";
        }
     }    
    más
     {
        // declaraciones
     }
Alen Alexander
fuente
0

Solo verifico una cadena nula con

if ([myString isEqual: [NSNull null]])

JerryZhou
fuente
0
if ([linkedStr isEqual:(id)[NSNull null]])
                {
                    _linkedinLbl.text=@"No";
                }else{
                    _linkedinLbl.text=@"Yes";
                }
SWAMY CHUNCHU
fuente
1
Si bien este fragmento de código puede responder la pregunta, no proporciona ningún contexto para explicar cómo o por qué. Considere agregar una o dos oraciones para explicar su respuesta.
brandonscript
0
if ([strpass isEqual:[NSNull null]] || strpass==nil || [strpass isEqualToString:@"<null>"] || [strpass isEqualToString:@"(null)"] || strpass.length==0 || [strpass isEqualToString:@""])
{
    //string is blank  
}
saurabh rathod
fuente
0

Para cadena:

+ (BOOL) checkStringIsNotEmpty:(NSString*)string {
if (string == nil || string.length == 0) return NO;
return YES;

}

Consulte la imagen a continuación:

ingrese la descripción de la imagen aquí

AmyNguyen
fuente
0

Para cadena:

+ (BOOL) checkStringIsNotEmpty:(NSString*)string {
if (string == nil || string.length == 0) return NO;
return YES;}
AmyNguyen
fuente