2010-09-15 7 views
18

Comment vérifier si un objet NSNumber est nul ou vide?vérifier si NSNumber est vide

nul OK est facile:

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

Mais si l'objet a été créé, mais il n'y a pas de valeur parce que la cession a échoué, comment puis-je vérifier? Utilisez quelque chose comme ça?

if ([myNumber intValue]==0) 
    doSomething 

Y at-il une méthode générale pour tester des objets sur le vide comme pour NSString disponibles (voir ce post)?

Exemple 1

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

Quelle valeur ne emptyNumber contient-il? Comment puis-je vérifier si emptyNumber est vide?

Exemple 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'arrive-t-il si j'utilise ceci après emptyNumber a été mis à zéro?

[emptyNumber intValue] 

Est-ce que je reçois zéro?

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

Comme cette façon NSLog est jamais appelé. myEmptyValue n'est pas nil et pas NSNull. Donc, il contient un nombre arbitraire?

+0

@ [0.7] donneront un NSNumber n'est certainement pas zéro, mais intValue retournera 0. Donc c'est un mauvais test. – gnasher729

+0

Refusé pour le grand détail qui a aidé à expliquer quelque chose que j'ai affaire par défaut. NSNumber * savedPin = [[NSUserDefaults standardUserDefaults] valueForKey: @ "someKey"]; renvoie un objet qui a la classe __NSCFConstantString et donc les comparaisons à nil échouaient. MERCI! –

Répondre

12

NSValue, , ... sont censés être créés à partir d'une valeur et en conserver toujours un. Le test d'une valeur spécifique telle que 0 ne fonctionne que s'il ne se trouve pas dans la plage des valeurs valides avec lesquelles vous travaillez.

Dans les rares cas où le code est plus simple pour travailler avec si vous avez une valeur qui représente « invalide » ou « non défini » et vous ne pouvez pas utiliser nil (par exemple, avec les conteneurs standard) vous pouvez utiliser NSNull à la place.

Dans votre premier exemple cela pourrait être:

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

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

Mais notez que vous ne pouvez pas insérer (ou supprimer) cette valeur à moins que vous devez différencier nil (c.-à-pas dans le conteneur) et, dire "invalide":

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

Quant au deuxième exemple, -intValue donner s vous 0 - mais simplement parce que l'envoi de messages à nil renvoie 0. Vous pouvez également obtenir 0 par exemple. pour un NSNumber dont intValue a été défini sur 0 avant, ce qui pourrait être une valeur valide.
Comme je l'ai déjà écrit ci-dessus, vous ne pouvez faire quelque chose comme ceci si 0n'est pas une valeur valide pour vous. Notez le pour vous, ce qui fonctionne le mieux dépend entièrement de vos besoins.

Permettez-moi de résumer :

Option 1:

Si vous n'avez pas besoin de toutes les valeurs de la plage de nombres, vous pouvez utiliser un (ou 0-1 ou .. .) et -intValue/... pour représenter spécifiquement "vide". Ce n'est apparemment pas le cas pour vous.

Option # 2:

Il vous suffit de ne pas enregistrer ou supprimer les valeurs du récipient si elles sont "vide":

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

Cela signifie cependant qu'il n'y a différence entre les clés vides et les clés qui n'existent jamais ou sont illégales.

Option 3:

Dans certains cas, rares il est plus commode de garder toutes les clés dans le dictionnaire et représentent « vide » avec une valeur différente. Si vous ne pouvez pas utiliser un de la gamme de numéros, nous devons mettre quelque chose différemment dans NSNumber n'a pas un concept de "vide". Le cacao a déjà NSNull pour de tels cas:

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

Cette option vous permet maintenant de faire la différence entre « vide », « non vide » et « pas dans le conteneur » (clé par exemple illégale).

+0

J'ai édité mon poste. Comment puis-je tester la vacuité dans ce «cas particulier»? Est-ce dans la gamme des valeurs valides ici? – testing

+0

Vous insérez '[NSNull null]' pour tester plus tard un objet NSNumber sur le vide. OK, mais quels sont les conteneurs standards? Je ne peux pas garantir quelle valeur est assignée à mon objet NSNumber. Donc je ne sais pas quand insérer 'nil' ou' NSNull'. Dans mon exemple, il pourrait aussi s'agir d'une chaîne vide.Devrais-je d'abord tester la valeur de retour de 'objectForKey' s'il s'agit d'une chaîne vide et ensuite je devrais insérer' nil' ou 'NSNull' dans mon objet NSNumber? Je pense que je devrais toujours insérer zéro, sauf si j'ai besoin de NSNull pour certains cas. Voir mon deuxième exemple. – testing

+1

@testing: Les conteneurs standard sont ceux de Cocoa Touch («NSArray», «NSDictionary», ...). Le premier exemple de test pour l'objet étant 'NSNull', le second suppose * que vous ne mettez pas la valeur dans le conteneur * - vous ne pouvez pas insérer' nil' dans ceux-ci, 'nil' représente *" pas dans le conteneur " *. Vous devez simplement décider si vous devez faire la distinction entre * "invalide" */* "inexistant" * et * "non dans le conteneur" *. Votre dernière phrase est proche de ce que je dis - soit ne la mettez pas dans le conteneur (donc vous obtenez 'nil' pour' -objectForKey: ... ') ou allez avec' NSNull'. –

3

NSNumber est soit nil, ou il contient un nombre, rien entre les deux. La "vacuité" est une notion qui dépend de la sémantique de l'objet particulier et, par conséquent, cela n'a pas de sens de rechercher une vérification générale de la vacuité.

En ce qui concerne vos exemples, il y a plusieurs choses qui se passent:

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

Le NSLog imprimera 0 ici, mais seulement parce qu'il ya une méthode intValue dans NSString. Si vous changez le message à quelque chose qui ne NSNumber peut faire, le code échouera:

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

Ce jetteront:

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

Ce qui signifie que vous êtes pas obtenir une valeur « vide » générale de retour du hachage, vous obtenez juste le NSString que vous avez stocké là.

Lorsque vous avez un vide (== nil) NSNumber et lui envoyer un message, le résultat sera zéro.C'est tout simplement une convention de langage qui simplifie le code:

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

va se transformer en ceci:

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

Hope this helps.

+0

Alors, que fait NSNumber * test = [NSNull null]? –

+1

Comme écrit, ce code n'a pas beaucoup de sens. NSNull est simplement une "version d'objet de la valeur nulle" et la seule raison pour laquelle il existe est de représenter une valeur "vide" dans les collections qui ne peuvent pas stocker nil directement. – zoul

+0

Merci, oui, je suppose que je suis juste en train d'essayer d'être clair dans mon esprit exactement quelle gamme de possibilités que je dois prendre en compte pour NSNumber –

0

NSNumber s sont immuables et ne peuvent être créés qu'avec une méthode usine ou une méthode initiale qui leur donne une valeur numérique. Autant que je sache, il n'est pas possible de se retrouver avec un NSNumber 'vide', sauf si vous comptez 0.

0

Il est très courant (pour moi au moins) de sortir un objet d'un dictionnaire, attendez-vous à ce qu'il se passe être un NSNumber et ensuite le renvoyer un objet nul. Si cela se produit et que vous faites un intValue, il va planter. Ce que je fais est la configuration de la protection nil car je préfère obtenir une valeur par défaut que d'un accident.

Une façon est la suivante:

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

et j'ai un comme pour flotteurs. Ensuite, vous obtenez au moins votre valeur par défaut. Une autre façon est de créer simplement une méthode de protection nul ..

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

Que l'on vous appelleriez comme ceci:

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

Faire face à Swift 2.0 et Parse:

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

Dans mon cas, je devais alors:

let myNumberIntValue = myNumber!.intValue 
Questions connexes