Qual è il modo giusto per verificare una stringa nulla in Objective-C?


184

Lo stavo usando nella mia app per iPhone

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

ma genera qualche eccezione e la console mostra che il titolo è "(null)".

Quindi sto usando questo ora:

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

Qual è la differenza e qual è il modo migliore per determinare se una stringa è nulla?


Risposte:


395

Come altri hanno sottolineato, ci sono molti tipi di "null" in Cocoa / Obiettivo C. Ma un'altra cosa da notare è che [title isKindOfClass: [NSNull class]] è inutilmente complesso poiché [NSNull null] è documentato come un singleton in modo da poter verificare l'uguaglianza del puntatore. Vedi Argomenti per Cacao: Usare Null .

Quindi un buon test potrebbe essere:

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

Nota come puoi usare il fatto che anche se title è zero, title.length restituirà 0 / nil / false, ovvero 0 in questo caso, quindi non è necessario un caso speciale. Questo è qualcosa a cui le persone che non conoscono l'Obiettivo C hanno difficoltà ad abituarsi, in particolare provenienti da altre lingue in cui messaggi / metodi chiamano a zero crash.


Grazie! Tuttavia, ho posto questa domanda in primo luogo perché stavo ottenendo un'eccezione perché il "titolo" null.
Teo Choong Ping,

1
Che tipo dovrebbe essere il titolo? Se si tratta di una NSString, ad esempio, ricevo il seguente avviso: il confronto di tipi distinti di Objective-C 'struct NSNull *' e 'struct NSString *' non ha un cast C'è un modo per rimuovere questo (non so se le cose sono cambiate da questa domanda è stata posta)?
thebossman il

1
Mi serve bene per pubblicare il codice senza compilarlo ;-). il titolo è presumibilmente un NSString, ma indipendentemente dal tipo di titolo, è sufficiente eseguire il cast di null al tipo di ID generico: (id) [NSNull null].
Peter N Lewis,

1
@JLT nil e [NSNull null] non saranno più gli stessi. [NSNull null] è un oggetto singleton che può essere utilizzato come supporto per zero quando non è possibile utilizzare zero (ad esempio in un valore NSArray o NSDictionary). Pertanto, un caso d'uso potrebbe essere quello in cui si disponeva di un NSArray di stringhe facoltative, alcune delle quali potrebbero essere nulle e si utilizza [NSNull null] nell'array per i casi nulli. In pratica, il test è raramente necessario, solo quando tu (o una libreria che usi!) Usi attivamente [NSNull null] come segnaposto.
Peter N Lewis,

1
Venire qui da Flutter e cercare il motivo per cui Mapil valore di un oggetto - che si trova nullin Dart - non corrisponde nilo NULLnell'Obiettivo C. Il motivo era che in realtà NUNull nullnon è il NULLnulla. Grazie @PeterNLewis!
Aleksandar,

25

è semplice come

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

ricorda che nell'obiettivo C se l'oggetto è null restituisce 0 come valore.

Questo ti darà sia una stringa nulla che una stringa di lunghezza 0.


49
Questo non funzionerà se l'oggetto è NSNull, è comunque necessario verificarlo prima in modo esplicito.
Jeremy Mack

6
potresti anche creare una categoria per NSNull per farlo tornare 0 al messaggio di lunghezza :)
Mihai Timar

1
Sì, questo si bloccherà se l'oggetto è NSNull.
Mike Gledhill,

Questo si bloccherà se l'oggetto è uguale a NSNull
joan

1
Oltre al problema del selettore non riconosciuto di NSNull, ciò non farà distinzione tra un puntatore NSString nullo o un NSString effettivamente presente ma essenzialmente una stringa vuota. (Ad esempio come letterale object = @"";o object = nil;)
KellyTheDude,

6

Fare riferimento ai seguenti articoli correlati su questo sito:

Penso che il tuo errore sia correlato a qualcos'altro in quanto non dovresti dover fare il controllo extra.

Vedi anche questa domanda correlata: controllo corretto della colonna di testo zero sqlite


Fastidiosamente Non ho abbastanza "punti" per aggiungere un secondo collegamento ipertestuale (anche a qualcosa su questo sito) Vedi anche: - stackoverflow.com/questions/598396/...
Timm

...permettimi. Anche se dovresti essere in grado di modificare i tuoi post dal rappresentante 0.
Rog

Grazie - è stato molto gentile. Quando ho scritto il mio post iniziale diceva che qualcosa come i nuovi utenti può aggiungere solo 1 hyperlink (che sembra un po 'duro - specialmente per i collegamenti incrociati in questo sito).
TimM,

6

Ho scoperto che per farlo davvero bene devi finire per fare qualcosa di simile

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

Altrimenti si verificano strane situazioni in cui il controllo ignorerà comunque il controllo. Non ne ho mai trovato uno che riesca a superare i isEqualcontrolli di lunghezza.


5

Che cosa succede con tutte queste "risposte per me"? Stiamo tutti codificando nella stessa lingua e le regole lo sono

  1. Assicurarsi che il riferimento non sia nullo
  2. Controlla e assicurati che la lunghezza della stringa non sia 0

Questo è ciò che funzionerà per tutti. Se una determinata soluzione "funziona solo per te", è solo perché il flusso dell'applicazione non consente uno scenario in cui il riferimento può essere nullo o la lunghezza della stringa deve essere 0. Il modo corretto per farlo è il metodo che gestirà quello che vuoi in tutti i casi.


4
Se il riferimento è nil(nota: non "null"), quindi l'invio di un messaggio, come length, produrrà 0 (o il valore 0 appropriato per il tipo restituito dal metodo). Questa è la regola della lingua. Non è necessario controllare nilseparatamente in questo caso.
jscs,

Ho detto null semplicemente a causa delle abitudini C ++ e se il tuo codice chiama metodi su oggetti nil, è probabile che il tuo codice sia rotto. Scoprirai che i metodi di chiamata su NULL / NIL (stesso concetto) sono generalmente una cattiva idea in qualsiasi lingua. Solo perché obj-c ti permette di fare qualcosa del genere non significa che dovresti semplicemente passare in giro oggetti nulli e provare a usarli senza preoccuparti.
nenchev,

1
L'invio della lunghezza a zero produce 0 - MA l'invio della lunghezza a NSNull produce un'eccezione.
cdstamper,

@nenchev Nessuno dice nulla riguardo al solo passaggio di oggetti nulli, ma il controllo di zero, quindi la chiamata di un metodo e l'utilizzo del suo valore di ritorno è peggiore dell'IMO rispetto all'utilizzo di una funzione del linguaggio come è pensata per essere utilizzata e verificare in seguito la validità del valore di ritorno del metodo.
Kevin,

@Kevin Non sono sicuro di come sia davvero peggio, solo perché è una caratteristica del linguaggio non significa che sia eccezionale. Non verificare se il suo null potrebbe aprire un percorso di codice che potrebbe portare a un errore di runtime più difficile da tracciare. Di solito è meglio verificare che i tuoi input siano come ti aspetti e reagire di conseguenza in caso contrario. Personalmente non mi piace la "caratteristica" di non ottenere eccezioni di runtime quando si tenta di inviare un messaggio a un oggetto nullo, poiché spesso rende più facile perdere alcuni bug di runtime.
nenchev,

4

Se si desidera eseguire il test su tutti gli oggetti nulli / vuoti (come stringhe vuote o matrici / set vuoti) è possibile utilizzare quanto segue:

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);
}

2
Questo in realtà non controlla object == [NSNull null] che probabilmente avrebbe senso.
Peter N Lewis,

3

Esistono due situazioni:

È possibile che un oggetto sia [NSNull null]o sia impossibile.
La tua applicazione di solito non dovrebbe usarla, ma [NSNull null];usala solo se vuoi mettere un oggetto " null " in un array o usarlo come valore di dizionario. E quindi dovresti sapere quali array o dizionari potrebbero contenere valori null e quali no.
Se ritieni che un array non contenga mai [NSNull null]valori, non verificarlo. Se esiste [NSNull null], potresti ottenere un'eccezione, ma va bene: le eccezioni Objective-C indicano errori di programmazione. E hai un errore di programmazione che deve essere risolto modificando un po 'di codice.

Se un oggetto potrebbe essere [NSNull null], allora lo controlli semplicemente testando
(object == [NSNull null]). Chiamare isEqualo controllare la classe dell'oggetto non ha senso. C'è solo un [NSNull null]oggetto e il semplice vecchio operatore C lo controlla nel modo più semplice ed efficiente.

Se controlli un NSStringoggetto che non può essere [NSNull null](perché sai che non può essere [NSNull null]o perché hai appena verificato che sia diverso da [NSNull null], allora devi chiederti come vuoi trattare una stringa vuota, cioè una con lunghezza 0. Se tu trattarlo è una nullstringa come nil, quindi test (object.length == 0). object.length restituirà 0 se object == nil, quindi questo test copre zero oggetti e stringhe con lunghezza 0. Se trattate una stringa di lunghezza 0 diversa da una stringa nulla, controllate semplicemente se object == nil.

Infine, se si desidera aggiungere una stringa a un array o un dizionario e la stringa potrebbe essere nulla, è possibile scegliere di non aggiungerla, sostituirla con @""o sostituirla [NSNull null]. Sostituendolo con @""si perde la capacità di distinguere tra "nessuna stringa" e "stringa di lunghezza 0". Sostituirlo con [NSNull null]significa che è necessario scrivere codice quando si accede alla matrice o al dizionario che verifica la presenza di [NSNull null]oggetti.


Molto lungo, ma questo va bene. NSNull dovrebbe apparire SOLO IN SINGLETONS! Tutta questa domanda non ha senso, mi dice che il programmatore non stava facendo qualcosa di corretto, e molti altri in futuro, non hanno letto il manuale / buona pratica del codice
Stephen J,

2

Basta controllare zero

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

o

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

2

Soluzione MACRO (2020)

Ecco la macro che uso per una stringa sicura invece di ottenere una stringa " (null) " su un UILabel, ad esempio:

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

supponiamo di avere una classe membro e la proprietà name e il nome è nullo:

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

con macro:

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

bello e pulito 😊

Extension Solution (2020)

Se preferisci controllare lo zero e la stringa vuota nel tuo progetto, puoi utilizzare la mia linea di estensione di seguito:

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

Esempio di utilizzo

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



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");
}

Funzionerebbe con i seguenti casi, NSString *strOne = @""OR NSString *strOne = @"StackOverflow"OR NSString *strOne = [NSNull null]OR NSString *strOne.


0

Se quel genere di cose non esiste già, puoi creare una categoria NSString:

@interface NSString (TrucBiduleChoseAdditions)

- (BOOL)isEmpty;

@end

@implementation NSString (TrucBiduleChoseAdditions)

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

@end

Questo è probabilmente eccessivo e non credo che risolverà questo problema.
Rog,

9
Self == nil è inutile: se self fosse zero, l'Obiettivo C non ti chiamerebbe in primo luogo. [(NSString *) nil isEmpty] restituisce semplicemente 0 / nil / false senza mai chiamare il tuo codice.
Peter N Lewis,

4
In realtà, oltre a ciò, [(NSString *) nil isEmpty] restituirà false. Quando si scrivono tali metodi dell'Obiettivo C, è meglio definirli in modo che lo zero / zero / falso di nil abbia un senso, quindi scrivere il metodo come hasCharacters sarebbe meglio. Nota che la lunghezza funziona già per questo, poiché puoi usare if (s.length) ovunque tu voglia usare if (! S.isEmpty) e s.length restituiranno correttamente 0 per il caso s == nil.
Peter N Lewis,

Questo è un grave incidente. Hai implementato "isEmpty" per NSString, ma se in realtà è NSNull, isEmpty verrà inviato a NSNull e andrà in crash perché non risponde a quel messaggio!
daniel.gindi,

0

Ciò che funziona per me è if ( !myobject )


3
Questo non funziona per oggetti null, solo oggetti zero. Ad esempio ... 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 .. mi dispiace per la formattazione, ma il codice verrà compilato :)
Rik Smith-Unna

0

Il controllo completo di una stringa per condizioni null può essere il seguente: <\ br>

    se (Stringa)
     {
       if ([mystring isEqualToString: @ ""])
        {
          mystring = @ "some string";
        }
     }    
    altro
     {
        // dichiarazioni
     }

0

Controllo solo la stringa null con

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


0
if ([linkedStr isEqual:(id)[NSNull null]])
                {
                    _linkedinLbl.text=@"No";
                }else{
                    _linkedinLbl.text=@"Yes";
                }

1
Sebbene questo frammento di codice possa rispondere alla domanda, non fornisce alcun contesto per spiegare come o perché. Valuta di aggiungere una o due frasi per spiegare la tua risposta.
brandonscript

0
if ([strpass isEqual:[NSNull null]] || strpass==nil || [strpass isEqualToString:@"<null>"] || [strpass isEqualToString:@"(null)"] || strpass.length==0 || [strpass isEqualToString:@""])
{
    //string is blank  
}

0

Per stringa:

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

}

Fare riferimento all'immagine seguente:

inserisci qui la descrizione dell'immagine


0

Per stringa:

+ (BOOL) checkStringIsNotEmpty:(NSString*)string {
if (string == nil || string.length == 0) return NO;
return YES;}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.