Pregunta

Estoy intentando crear un método que compruebe si hay una cadena nula/nula/vacía, y estoy intentando que funcione como una categoría, pero no tengo suerte.

Estoy usando este código, basado en las respuestas en este tema:

@implementation NSString (NSStringExtension)
- (BOOL)isNullOrEmpty {
    return self == nil || 
    self == (id)[NSNull null] ||
    [@"" isEqualToString:self] || 
    [[self stringByReplacingOccurrencesOfString:@" " withString:@""] length] == 0||
    [self isEqualToString:@"(null)"]
     || ([self respondsToSelector:@selector(length)] && [(NSData *) self length] == 0)
     || ([self respondsToSelector:@selector(count)] && [(NSArray *) self count] == 0)
     || [[self stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] length] == 0;
}
@end

Sin embargo, cuando intento usar esto, esto es lo que obtengo:

NSLog([@"" isNullOrEmpty] ? @"1":@"0"); // prints 1
NSString *s1 = nil;
NSLog([s1 isNullOrEmpty] ? @"1":@"0"); // prints 0
NSLog([args.itemName isNullOrEmpty] ? @"1":@"0"); // prints 0
NSLog([(NSString*)nil isNullOrEmpty] ? @"1":@"0"); // prints 0

Esto me desconcierta, y sólo puedo suponer que alguna combinación de iOS5/ARC está provocando que el objeto nulo sea forzado a una cadena/puntero en blanco.El depurador muestra la cadena como 0x0, pero cuando uso mi isNullOrEmpty método, me sale falso.

¿Fue útil?

Solución

return self == nil

Esto nunca puede suceder.Si intentas enviar isNullOrEmpty (o cualquier otro mensaje) a nil, no pasa nada (objc_msgSend(), la función responsable del envío de mensajes, comprueba si hay un nil receptor como una de las primeras cosas que hace y aborta).

self == (id)[NSNull null]

Esto tampoco sucederá nunca.Si tu envías isNullOrEmpty a un objeto que es una instancia de NSNull, su método aquí, que es un método en NSString, no será llamado.En cambio, NSNullLa versión (que probablemente no existe) será.

Asimismo, ([self respondsToSelector:@selector(count)] && [(NSArray *) self count]) nunca va a suceder.Si el objeto es un NSArray, entonces isNullOrEmpty nunca se ejecutará, porque, nuevamente, es un método de NSString.

En consecuencia, [(NSData *) self length] no hace lo que crees que hace. NSString instancias hacer responder a length, pero lanzando el objeto a NSData no usa el NSData versión del método: todavía termina como la NSString versión de length, porque el objeto en realidad es un NSString (La transmisión solo ocurre en tiempo de compilación;no puede cambiar nada en tiempo de ejecución).

[self isEqualToString:@"(null)"]

Aquí parece que estás comprobando nil otra vez, pero estás siendo engañado por el representación eso NSLog elige cuando imprime nil:

NSLog(@"%@", nil);

Esto muestra (null) en la consola, pero eso no significa que el objeto en sí sea una cadena con esos caracteres. NSLog simplemente elige esa cadena para mostrar nil.*

Varias de las cosas que estás haciendo requerirían que esto esté en una categoría en NSObject, de modo que el método haría de hecho ser llamado incluso si el objeto no era un NSString.

Para verificar una cadena que consta solo de espacios en blanco, todo lo que necesita es la comparación con la cadena vacía @"" después de recortar los espacios en blanco:

NSString * trimmedSelf = [self stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
// Then either:
[trimmedSelf isEqualToString:@""];
// Or:
([trimmedSelf length] == 0);

*Y aún mejor, haciendo NSLog(@"%@", [NSNull null]); muestra <null> (corchetes angulares en lugar de paréntesis), maravillosamente confuso las primeras veces que te encuentres NSNull.

Otros consejos

Otro enfoque puede ser definir una macro simple.

#define NSStringIsNullOrEmpty(str) ((str==nil) || [(str) isEqualToString:@""])

Es simple y efectivo.Si no te gustan las macros, siempre puedes convertirlas en una llamada de función sin afectar el resto de tu código.

-- Actualizar:

@Bryan ha planteado un buen punto.Una función en línea es una excelente manera de hacerlo.Aquí hay una macro actualizada que evaluará str solo una vez.

#define NSStringIsNullOrEmpty(str) ({ NSString *_str=(str); ((tmp==nil) || [tmp isEqualToString:@""]);})

En Objective-C, enviar un mensaje a cero siempre devolverá 0 (o NO, una estructura puesta a cero, NULL, etc., según el tipo de retorno declarado).El isNullOrEmpty El método que usted escribió en realidad no será invocado cuando envíe isNullOrEmpty a nil.Vea la respuesta aceptada a ¿Enviando un mensaje a cero? para más información.

Quizás podrías cambiar tu método para ser isNotNullOrEmpty.Luego un valor de retorno de 0 al enviar isNotNullOrEmpty a nil tendrá sentido.

No estás llamando a tu método, pero enviando un mensaje a cero.

Este es el comportamiento esperado.Estás enviando un mensaje a nil después de todo.Por lo tanto, devuelve nil (o algún otro valor 0).Qué cortocircuitos a falso para que se imprima '0' en los casos que se muestran a continuación:

NSLog([s1 isNullOrEmpty] ? @"1":@"0"); // prints 0
NSLog([(NSString*)nil isNullOrEmpty] ? @"1":@"0"); // prints 0

Incluso puede confirmar que su mensaje no se llama en esos casos estableciendo un punto de interrupción en su nuevo método de categoría.

Como otros han dicho, llamar [nil isNullOrEmpty]; En realidad, no ejecutará su método.El nil objeto es solo eso:vaciarse.

Como solución, me gustaría decir que no es porque estés en un lenguaje orientado a objetos que nunca debes usar funciones.

BOOL IsStringNilOrEmpty(NSString*)str
{
    return str == nil ||
        str == null ||
        [@"" isEqualToString:str] ||
        [[str stringByReplacingOccurrencesOfString:@" " withString:@""] length] == 0||
        [str isEqualToString:@"(null)"]
        || ([str respondsToSelector:@selector(length)] && [(NSData *) str length] == 0)
        || ([str respondsToSelector:@selector(count)] && [(NSArray *) str count] == 0)
        || [[str stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] length] == 0;   
}

De hecho, acabo de solucionar este problema dándole la vuelta así

-(BOOL) isNotNullOrWhiteSpace
{
        return [self length] != 0 && [[self stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] length] != 0;
}

entonces, en lugar de isNullOrWhiteSpace, es isNotNullOrWhiteSpace.

Este es mi método para verificar nulo/vacío

-(nsstring*) nullinputinitWithString: (nsstring*) inputString {

if( (InputString == nil) ||(InputString ==(NSString*)[NSNull null])||([InputString isEqual:nil])||([InputString length] == 0)||([InputString isEqualToString:@""])||([InputString isEqualToString:@"(NULL)"])||([InputString isEqualToString:@"<NULL>"])||([InputString isEqualToString:@"<null>"]||([InputString isEqualToString:@"(null)"])||([InputString isEqualToString:@"NULL"]) ||([InputString isEqualToString:@"null"])))

    return @"";
else
    return InputString ;

}

¿Has pensado en crear un método de clase en una categoría que extienda NSString?

NSString+NSStringExtensions.h

#import <Foundation/Foundation.h>

@interface NSString(NSStringExtensions)
+(BOOL)isNilOrEmpty:(NSString*)string;
@end

NSString+NSStringExtensions.m

#import "NSString+NSStringExtensions.h"

@implementation NSString(NSStringExtensions)

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

@end

Entonces lo usas así:

#import "NSString+NSStringExtensions.h"
...
NSLog([NSString isNilOrEmpty:@""] ? @"1":@"0");
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top