web-dev-qa-db-fra.com

Vérifier si la clé existe dans NSDictionary est nulle ou non

J'ai cherché comment vérifier si la clé NSDictionary existe ou non et j'ai trouvé la solution. Mais cela me lance quand même une erreur en ajoutant une valeur nulle à la clé. Je ne sais pas si mon code est correct ou non. Si quelqu'un a une idée à ce sujet, il peut m'aider.

NSDictionary *result;
id myImageURL = [result objectForKey:@"url"];
if ((NSNull *)myImageURL == [NSNull null])
    myImageURL = @"";

id myImage = [result objectForKey:@"image"];
if ((NSNull *)myImage == [NSNull null])
    myImage = @"";

Vérifiez si null n’ajoute rien et si non, ajoutez la valeur. Mais cela me donne toujours une erreur, je ne sais pas pourquoi.

/****OUTPUT*****/

2011-08-11 14:56:06.668 Tab_Table_Win[6510:207] RESULTS : {
image = "<UIImage: 0xbc332c0>";
url = "http://a3.twimg.com/profile_images/999228511/normal.jpg";
}

2011-08-11 14:56:06.669 Tab_Table_Win[6510:207] url : http://a3.twimg.com/profile_images/999228511/normal.jpg
2011-08-11 14:56:06.670 Tab_Table_Win[6510:207] IMage : <UIImage: 0xbc332c0>

/*****Breaks Here ***/

2011-08-11 14:56:06.876 Tab_Table_Win[6510:207] RESULTS : {
}
2011-08-11 14:56:06.878 Tab_Table_Win[6510:207] url : (null)
2011-08-11 14:56:06.879 Tab_Table_Win[6510:207] IMage : (null)
2011-08-11 14:56:06.881 Tab_Table_Win[6510:207] *** Terminating app due to uncaught    exception 'NSInvalidArgumentException', reason: '-[__NSCFDictionary setObject:forKey:]: attempt to insert nil key'
14
lifemoveson

La réponse correcte est:

NSDictionary *result;
NSURL *myImageURL = [result objectForKey:@"url"];
UIImage *myImage = [result objectForKey:@"image"];

/**** Correct way ****/
if (myImageURL != nil && myImage != nil) {
    [images setObject:myImage forKey:myImageURL];
}

Merci pour toutes les explications.

14
lifemoveson

Tommy a parfaitement expliqué cela.

Ce que je recommande est de créer une extension de la classe NSDictionary comme suit:

#import <Foundation/Foundation.h>

@interface NSDictionary (Safety)

- (id)safeObjectForKey:(id)aKey;

@end

Et le fichier d'implémentation:

#import "NSDictionary+Safety.h"

@implementation NSDictionary (Safety)

- (id)safeObjectForKey:(id)aKey {
  NSObject *object = self[aKey];

  if (object == [NSNull null]) {
    return nil;
  }

  return object;
}

@end

Et au lieu d'utiliser [dictionary objectForKey:@"keyName"]; dans votre code, utilisez

[dictionary safeObjectForKey:@"keyName"];

Ainsi, comme l'explique Tommy, vous enverriez un appel de méthode à un élément null qui ne planterait pas l'application, mais votre objet obtiendrait une valeur nulle.

J'espère que cela t'aides.

13
c1pherB1t

la réponse ci-dessous a fonctionné pour moi: 

https://stackoverflow.com/a/2784675/936957

if ([dictionary objectForKey:key]) {
    // previously stored data for "key"
}

Notez également que vous pouvez obtenir un tableau des clés dans un dictionnaire en utilisant

[dictionary allKeys]
7
Yunus Nedim Mehel

Chaque fois que j'essaie de vérifier si un objet renvoyé par un dictionnaire est null, je le fais:

id obj = [myDictionary objectForKey:entityKeyName];
if (obj == [NSNull null]) {
    // do something 
}

Ensuite, dans votre code, ce serait:

NSDictionary *result;
NSString *myImageURL = [result objectForKey:@"url"];
if (myImageURL == [NSNull null])
     myImageURL = @"";

C'est ce que je ferais dans votre code.

De plus, le résultat de NSDictionary est-il défini? Dans votre code, rien ne le configure. Il est juste défini comme variable que vous prévoyez d'utiliser des résultats appelés

6
serenn

Si un objet n'existe pas pour une clé, NSDictionary retournera nil. Un NSNull est un objet réel, et donc une chose distincte. C'est comme la distinction entre pouvoir enregistrer qu'il y avait une valeur et la valeur comme nulle, et ne pas enregistrer s'il y avait une valeur. Cela dépend aussi un peu de votre pensée en termes C de l'indirection d'un pointeur vers un objet plutôt que simplement d'un objet, de sorte que ce n'est pas complètement sémantique de ce point de vue.

En Objective-C, vous pouvez envoyer n’importe quel message à nil et le résultat obtenu est nil (ou 0). Donc, si votre code est conçu pour garantir que vous avez une référence d'objet sécurisé, comme vous le feriez peut-être en C++, ce que vous faites est inutile. Des énoncés composés comme:

object = [[Type alloc] init];

Sont toujours explicitement en sécurité, même si alloc échoue et renvoie nil. Tout ce qui va se passer, c'est que l'appel à init ne fera rien du tout et que l'objet se retrouvera avec la valeur nil car le résultat de l'envoi de init à nil est également nil.

Cela étant dit, les réponses fournies par Bill et Emmanuel devraient être correctes. Comparez votre résultat soit directement à nil, soit implicitement à zéro. Si vous rencontrez un plantage plus tard, je suppose que c'est parce que vous vous attendez à ce que myImageUrl et myImage soient des types autres que NSString (je remarque que vous avez utilisé le id sans type dans votre code d'origine) et vous leur envoyez un message. ne répond pas à.

4
Tommy

cette autre option: 

if (![result objectForKey:@"image"])
    {
        NSLog(@"doesn't exist");
    }
    if ([result objectForKey:@"image"])
    {
        NSLog(@"exist");
    }
2
Juan
NSDictionary *result;
NSString *myImageURL = [result objectForKey:@"url"];
if (myImageURL == NULL)
    myImageURL = @"";

NSString *myImage = [result objectForKey:@"image"];
if (myImageURL == NULL)
    myImage = @"";

Voyez si cela fonctionne, plutôt que de trop penser à la classe NULL.

2
Bill Burgess

ça ne marchait pas pour moi, je l'ai compris comme ça

id myImageURL = [result objectForKey:@"url"];
if ([myImageURL isKindOfClass:[NSNull class]])  
    myImageURL = @"";
1
lomec

Très bien voici la réponse que presque @Iomec avait presque

UIImage *myImage = ([result objectForKey:@"image"] != [NSNull null] ? [result objectForKey:@"image"] : nil);

C’est la bonne réponse car elle est nulle et quand vous dites myImage = [receiveObject ...]; alors si myImage = nil, vous convertissez une valeur nulle (nil) dans une classe qui est une exception, sinon un bogue en cours d'exécution.

Vous devez: 1) tester la valeur null NSNull 2) sinon, attribuer

Si votre code n'a pas encore été corrigé, il le sera en production lorsque vous exécuterez 8 applications en tâche de fond un jour.

1
Nick Turner

Lorsque vous appelez le dictionnaire objectForKeyin nullable, l'application se bloque, j'ai donc corrigé le problème de cette façon afin d'éviter tout blocage.

- (instancetype)initWithDictionary:(NSDictionary*)dictionary {
id object = dictionary;

if (dictionary && (object != [NSNull null])) {
    self.name = [dictionary objectForKey:@"name"];
    self.age = [dictionary objectForKey:@"age"];
}
return self;

}

0
Aleem

J'ai le même problème avec JSONKit. La mise en place il y a

 - (id)objectForKey:(id)aKey
{
  [...]
  return((entryForKey != NULL) ? entryForKey->object : NULL);
}

Donc, ceci retournera certainement NULL si l'objet n'est pas là. Je vérifie comme suit

NSArray* array = [myDictionary objectForKey:@"a"];
if((NSNull*)arrays!=[NSNull null])
{
  [...]
}
0
Jens Busch
     1. Results Dictionary after JSON parsing:

        //if hits success

        {"result":{"action":"authentication","statusCode":"200","statusMsg":"No
        error, operation
        successful.","count":1,"data":{"apiToken":"509e6d21-4f69-4ded-9f3d-4537e59e6a3a","userId":8,"role":"Bidder","firstName":"bidder","lastName":"bidder","emailAddress":"[email protected]","countiesCovered":"21,16,11,1,2,14,32,3,4,25,13,15,5,41,43,6,12,7,24,39,17,36,42,44,29,40,8,18,19,27,9,28,23,10,33,26,35,20,30,22,34,31"}}}

//Data is Dictionary inside Result


-----------------------------------------------------------------------
            I had an error showing : NULL DATACould not cast value of type 'NSNull' (0xda7058) to 'NSDictionary' (0xda6d74) and the result was
        the following.

            ({"result":{"action":"authentication","statusCode":"204","statusMsg":"Invalid
        Username or Password","count":null,"data":null}})

            I fixed the Null check of dictionary.

                                if (result.objectForKey("data") is NSNull)
                                {
            print ("NULL DATA")

                                }
                                else
                                {
                                    let data = result["data"]as! NSDictionary
                                    print (data)

                                }
0
A.G

Peut-être voudriez-vous ajouter un peu plus de sécurité en vérifiant pour vous assurer qu'il ne s'agit PAS d'une chaîne de caractères au lieu de simplement vérifier si IS est nul. (Pour vous assurer que ce n'est pas un nombre ou quoi que ce soit d'autre que vous pourriez ne pas vouloir.)

id myImageURL = [result objectForKey:@"url"];
if (![myImageURL isKindOfClass:[NSString class]]) {  
    myImageURL = @"";
}
0
Darkin