Quelle est la bonne façon de vérifier une chaîne nulle en Objective-C?


184

J'utilisais ceci dans mon application iPhone

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

mais cela lève une exception, et la console montre que le titre est "(null)".

Donc j'utilise ceci maintenant:

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

Quelle est la différence et quel est le meilleur moyen de déterminer si une chaîne est nulle?


Réponses:


395

Comme d'autres l'ont souligné, il existe de nombreux types de "null" sous Cocoa / Objective C. Mais une autre chose à noter est que [title isKindOfClass: [NSNull class]] est inutilement complexe puisque [NSNull null] est documenté comme singleton afin que vous puissiez simplement vérifier l'égalité des pointeurs. Voir Rubriques pour Cocoa: Utilisation de Null .

Un bon test pourrait donc être:

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

Notez comment vous pouvez utiliser le fait que même si title est nul, title.length renverra 0 / nil / false, c'est-à-dire 0 dans ce cas, vous n'avez donc pas à le cas particulier. C'est quelque chose auquel les nouveaux utilisateurs d'Objectif C ont du mal à s'habituer, en particulier à venir d'autres langages où les messages / méthodes d'appels à nil plantent.


Merci! Cependant j'ai posé cette question en premier lieu parce que je recevais une exception parce que le "titre" était nul.
Teo Choong Ping

1
Quel type est censé être le titre? Si c'est une NSString, par exemple, je reçois l'avertissement suivant: la comparaison des différents types Objective-C 'struct NSNull *' et 'struct NSString *' manque d'un cast Existe-t-il un moyen de supprimer cela (je ne sais pas si les choses ont changé depuis cette question a été posée)?
thebossman

1
Cela me sert à publier du code sans le compiler ;-). title est vraisemblablement une NSString, mais quel que soit le type de titre, il suffit de convertir null en type d'id générique: (id) [NSNull null].
Peter N Lewis

1
@JLT nil et [NSNull null] ne seront plus jamais les mêmes. [NSNull null] est un objet singleton qui peut être utilisé comme support pour nil lorsque nil ne peut pas être utilisé (par exemple dans une valeur NSArray ou NSDictionary). Ainsi, un cas d'utilisation peut être celui où vous avez un NSArray de chaînes facultatives, dont certaines peuvent être nulles, et vous utilisez [NSNull null] dans le tableau pour les cas nuls. En pratique, le test est rarement nécessaire, uniquement lorsque vous (ou une bibliothèque que vous utilisez!) Utilisez activement [NSNull null] comme espace réservé.
Peter N Lewis

1
Venant ici de Flutter, et cherchant la raison pour laquelle Mapla valeur d' un élément - qui est nulldans Dart - ne correspond pas à nilou NULLà l'Objectif C. La raison était qu'il s'agissait en fait NUNull null, pas de la valeur NULLnulle. Merci @PeterNLewis!
Aleksandar

25

c'est aussi simple que

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

rappelez-vous que dans l'objectif C, si l'objet est nul, il renvoie 0 comme valeur.

Cela vous donnera à la fois une chaîne nulle et une chaîne de longueur 0.


49
Cela ne fonctionnera pas si l'objet est NSNull, vous devez toujours le vérifier explicitement d'abord.
Jeremy Mack

6
vous pouvez également créer une catégorie pour NSNull pour qu'elle renvoie 0 à la longueur du message :)
Mihai Timar

1
Ouais, cela plantera si l'objet est NSNull.
Mike Gledhill

Cela plantera si l'objet est égal à NSNull
joan

1
En plus du problème de sélecteur non reconnu NSNull, cela ne fera pas la différence entre un pointeur NSString qui est nul ou un NSString qui est réellement là mais qui est essentiellement une chaîne vide. (Par exemple en tant que littéral object = @"";ou object = nil;)
KellyTheDude

6

Reportez-vous aux articles connexes suivants sur ce site:

Je pense que votre erreur est liée à autre chose car vous ne devriez pas avoir besoin de faire la vérification supplémentaire.

Voir également cette question connexe: Vérification correcte de la colonne de texte nil sqlite


Malheureusement, je n'ai pas assez de "points" pour ajouter un deuxième lien hypertexte (même vers quelque chose sur ce site) voir aussi: - stackoverflow.com/questions/598396/…
TimM

...autorise moi. Bien que vous devriez être en mesure de modifier vos propres messages depuis le rep 0.
Rog

Merci - c'était très gentil. Lorsque j'ai écrit mon message initial, il était dit que les nouveaux utilisateurs ne pouvaient ajouter qu'un seul lien hypertexte (ce qui semble un peu dur - en particulier pour les liens croisés sur ce site).
TimM

6

J'ai trouvé que pour vraiment faire les choses correctement, vous finissez par devoir faire quelque chose de similaire à

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

Sinon, vous obtenez des situations étranges où le contrôle contournera toujours votre chèque. Je n'en ai pas rencontré un qui dépasse les isEqualcontrôles de longueur et de longueur.


5

Qu'est-ce que toutes ces réponses "fonctionne pour moi"? Nous codons tous dans la même langue et les règles sont

  1. Assurez-vous que la référence n'est pas nulle
  2. Vérifiez et assurez-vous que la longueur de la chaîne n'est pas 0

C'est ce qui fonctionnera pour tous. Si une solution donnée "fonctionne uniquement pour vous", c'est uniquement parce que le flux de votre application n'autorisera pas un scénario dans lequel la référence peut être nulle ou la longueur de la chaîne à 0. La bonne façon de procéder est la méthode qui gérera ce que vous voulez dans tous les cas.


4
Si la référence est nil(note: pas "null"), alors l'envoi d'un message, comme length, produira 0 (ou la valeur 0 appropriée pour le type de retour de la méthode). C'est la règle de la langue. Il n'est pas nécessaire de vérifier nilséparément dans ce cas.
jscs

J'ai dit null simplement à cause des habitudes C ++, et si votre code appelle des méthodes sur des objets nil, il y a de fortes chances que votre code soit cassé. Vous constaterez que l'appel de méthodes sur NULL / NIL (même concept) est généralement une mauvaise idée dans n'importe quel langage. Ce n'est pas parce que obj-c vous permet de faire quelque chose comme ça que vous devriez simplement passer des objets nil et essayer de les utiliser sans vous en soucier.
nenchev

1
L'envoi de longueur à nil produit 0 - MAIS l'envoi de longueur à NSNull produit une exception.
cdstamper

@nenchev Personne ne dit rien sur le simple fait de passer des objets nil, mais vérifier nil, puis appeler une méthode et utiliser sa valeur de retour est pire que d'utiliser une fonctionnalité de langage comme elle est censée être utilisée et de vérifier la validité de la valeur de retour de la méthode par la suite.
Kevin

@Kevin Je ne sais pas comment c'est vraiment pire, juste parce que c'est une fonctionnalité de langage ne signifie pas que c'est génial. Ne pas vérifier si sa valeur nulle pourrait ouvrir un chemin de code qui pourrait entraîner une erreur d'exécution plus difficile à suivre. Il est généralement préférable de vérifier que vos entrées sont conformes à vos attentes et de réagir en conséquence si elles ne le sont pas. Personnellement, je n'aime pas la "fonctionnalité" de ne pas avoir d'exceptions d'exécution lorsque j'essaie d'envoyer un message à un objet nul, car cela permet souvent de rater plus facilement certains bogues d'exécution.
nenchev

4

Si vous souhaitez tester tous les objets nil / vides (comme des chaînes vides ou des tableaux / ensembles vides), vous pouvez utiliser ce qui suit:

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
Cela ne vérifie pas réellement l'objet == [NSNull null], ce qui aurait probablement un sens.
Peter N Lewis

3

Il existe deux situations:

Il est possible qu'un objet soit [NSNull null], ou c'est impossible.
Votre application ne devrait généralement pas [NSNull null];vous en servir uniquement si vous voulez mettre un objet " nul " dans un tableau ou l'utiliser comme valeur de dictionnaire. Et puis, vous devez savoir quels tableaux ou dictionnaires peuvent contenir des valeurs nulles et lesquels ne le sont pas.
Si vous pensez qu'un tableau ne contient jamais de [NSNull null]valeurs, ne le vérifiez pas. S'il y a un [NSNull null], vous pouvez obtenir une exception mais c'est très bien: les exceptions Objective-C indiquent des erreurs de programmation. Et vous avez une erreur de programmation qui doit être corrigée en modifiant du code.

Si un objet peut l' être [NSNull null], vous le vérifiez simplement en testant
(object == [NSNull null]). Appeler isEqualou vérifier la classe de l'objet n'a pas de sens. Il n'y a qu'un seul [NSNull null]objet, et l'ancien opérateur C le vérifie très bien de la manière la plus simple et la plus efficace.

Si vous cochez un NSStringobjet qui ne peut pas être [NSNull null](parce que vous savez qu'il ne peut pas l'être [NSNull null]ou parce que vous venez de vérifier qu'il est différent de [NSNull null], alors vous devez vous demander comment vous voulez traiter une chaîne vide, c'est-à-dire une chaîne de longueur 0. Si vous traiter c'est une nullchaîne comme nil, alors (object.length == 0)test.object.length renverra 0 si object == nil, donc ce test couvre les objets nuls et les chaînes de longueur 0. Si vous traitez une chaîne de longueur 0 différente d'une chaîne nulle, vérifiez simplement si object == nil.

Enfin, si vous souhaitez ajouter une chaîne à un tableau ou à un dictionnaire et que la chaîne peut être nulle, vous avez le choix de ne pas l'ajouter, de la remplacer par @""ou de la remplacer par [NSNull null]. Le remplacer par @""signifie que vous perdez la capacité de faire la distinction entre "aucune chaîne" et "chaîne de longueur 0". Le remplacer par [NSNull null]signifie que vous devez écrire du code lorsque vous accédez au tableau ou au dictionnaire qui vérifie les [NSNull null]objets.


Très long, mais c'est bien. NSNull devrait apparaître UNIQUEMENT DANS LES SINGLETONS! Toute cette question n'a aucun sens, me dit que le codeur n'a pas fait quelque chose de correct, et bien d'autres à l'avenir aussi, n'a pas lu le manuel / bonne pratique de code
Stephen J

2

Vous ne vérifiez rien

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

ou

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

2

Solution MACRO (2020)

Voici la macro que j'utilise pour une chaîne sûre au lieu d'obtenir une chaîne " (null) " sur un UILabel par exemple:

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

disons que vous avez une classe membre et une propriété de nom, et que le nom est nul:

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

avec macro:

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

agréable et propre?

Solution d'extension (2020)

Si vous préférez vérifier nil Null et chaîne vide dans votre projet, vous pouvez utiliser ma ligne d'extension ci-dessous:

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

Exemple d'utilisation

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

Cela fonctionnerait avec les cas suivants, NSString *strOne = @""OU NSString *strOne = @"StackOverflow"OU NSString *strOne = [NSNull null]OU NSString *strOne.


0

Si ce genre de chose n'existe pas déjà, vous pouvez créer une catégorie NSString:

@interface NSString (TrucBiduleChoseAdditions)

- (BOOL)isEmpty;

@end

@implementation NSString (TrucBiduleChoseAdditions)

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

@end

C'est probablement exagéré et je ne pense pas que cela résoudra ce problème.
Rog

9
Le self == nil est inutile - si le self était nul, l'Objectif C ne vous aurait pas appelé en premier lieu. [(NSString *) nil isEmpty] renverrait simplement 0 / nil / false sans jamais appeler votre code.
Peter N Lewis

4
En fait, en plus de cela, [(NSString *) nil isEmpty] retournera false. Lors de l'écriture de telles méthodes Objective C, il est préférable de les définir de sorte que 0 / nil / false de nil ait un sens, donc écrire la méthode comme hasCharacters serait mieux. Notez que la longueur fonctionne déjà pour cela, car vous pouvez utiliser if (s.length) partout où vous voudriez utiliser if (! S.isEmpty) et s.length renverra correctement 0 pour le cas s == nil.
Peter N Lewis

C'est un grave accident. Vous avez implémenté "isEmpty" pour NSString, mais si c'est réellement NSNull, alors isEmpty sera envoyé à NSNull, et plantera car il ne répond pas à ce message!
daniel.gindi

0

Ce qui fonctionne pour moi c'est if ( !myobject )


3
Cela ne fonctionne pas pour les objets nuls, uniquement pour les objets nuls. Par exemple ... 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 .. désolé pour le formatage, mais le code va se compiler :)
Rik Smith-Unna

0

La vérification complète d'une chaîne pour les conditions nulles peut être la suivante: <\ br>

    si (mystring)
     {
       if ([mystring isEqualToString: @ ""])
        {
          mystring = @ "une chaîne";
        }
     }    
    autre
     {
        // déclarations
     }

0

Je ne vérifie qu'une chaîne nulle avec

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


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

1
Bien que cet extrait de code puisse répondre à la question, il ne fournit aucun contexte pour expliquer comment ou pourquoi. Pensez à ajouter une phrase ou deux pour expliquer votre réponse.
brandonscript

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

0

Pour la chaîne:

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

}

Reportez-vous à l'image ci-dessous:

entrez la description de l'image ici


0

Pour la chaîne:

+ (BOOL) checkStringIsNotEmpty:(NSString*)string {
if (string == nil || string.length == 0) return NO;
return YES;}
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.