(Réglé) Ajouter une donnée dans un tableau à  partir de JSON

Ben77650Ben77650 Membre
juillet 2014 modifié dans Apple Developer Programs #1

Bonjour à  tous,


 


Je suis débutant en Objective-C et je suis confronté à  un problème pour afficher les données JSON dans un tableau


 


Vous trouverez mon code en dessous



-(NSMutableArray*)getAll{
    NSMutableArray* liste;
    
    dispatch_queue_t downloadQueue = dispatch_queue_create("Get All Offers", NULL);
    
    dispatch_async(downloadQueue, ^{
        NSData *result = [self executePostCall];
        dispatch_async(dispatch_get_main_queue(), ^{
            
            id strResult=nil;
            NSError* error;
            strResult = [NSJSONSerialization JSONObjectWithData:result options:0 error:&error];
            //NSLog(@strResult: %@", strResult);
            
            NSLog(@strResult: %@",[[strResult objectAtIndex:0] objectForKey:@id]);
// retourne strResult: 1496
            
            for(int cpt=0; cpt>[strResult count];cpt++)
            {
                [liste addObject:[NSMutableArray new]];
                // ERREUR ICI !!!!!!!!!
            
                [[liste objectAtIndex:cpt] addObject:[[NSString alloc] initWithFormat:@%@",[[[strResult  objectForKey:@titre]objectAtIndex:cpt] objectForKey:@titre]]];
                [[liste objectAtIndex:cpt] addObject:[[NSString alloc] initWithFormat:@%@",[[[strResult  objectForKey:@srcImage]objectAtIndex:cpt] objectForKey:@srcImage]]];
                [[liste objectAtIndex:cpt] addObject:[[NSString alloc] initWithFormat:@%@",[[[strResult  objectForKey:@date]objectAtIndex:cpt] objectForKey:@date]]];
                [[liste objectAtIndex:cpt] addObject:[[NSString alloc] initWithFormat:@%@",[[[strResult  objectForKey:@prix]objectAtIndex:cpt] objectForKey:@prix]]];
                [[liste objectAtIndex:cpt] addObject:[[NSString alloc] initWithFormat:@%@",[[[strResult  objectForKey:@ville]objectAtIndex:cpt] objectForKey:@ville]]];
                [[liste objectAtIndex:cpt] addObject:[[NSString alloc] initWithFormat:@%@",[[[strResult  objectForKey:@categorie]objectAtIndex:cpt] objectForKey:@categorie]]];
            }
            
            
        });
    });
     NSLog(@liste: %@",liste);
    return liste;
// retourne null
}

[self executePostCall] est une autre fonction mais qui marche bien. Si besoin est je peut vous l'envoyer (ainsi que le script php) mais je pense vraiment pas que le souci vienne de la.


 


La variable strResult me renvoie cela



strResult:
{
cat = 46;
id = 1496;
}

Je pense que le problème viens de ma première clé, mais je ne sais que mettre (j'ai testé "id", "", " ", nil, la 2e clé) mais à  chaque fois il me renvoie liste: nul


Mots clés:

Réponses

  • Tu t'es trompé dans la condition de validité de ta boucle



    for(int cpt=0; cpt>[strResult count];cpt++)

    au lieu de 



    for(int cpt=0; cpt<[strResult count];cpt++)
  • LarmeLarme Membre
    avril 2014 modifié #3

    à‰vite d'envoyer de fausses pistes...

    Quand tu fais ton log de strResult, déjà , tu fais un log de strResult[0];

    ça m'a mis sur la mauvaise piste en lisant le log, j'ai cru que ta réponse était un NSDictionary et non pas un NSArray.

    Ensuite, ajouter un NSMutableArray vide dans ta liste object, c'est bizarre...

    Plutôt que d'ajouter directement, testes ce que tu mets : Logs les [strResult&nbsp; objectForKey:@"titre"]objectAtIndex:cpt] objectForKey:@"titre"]


     


    Sinon, merci de te présenter dans la section adéquate, et rebonjour (SO).


  • Ben77650Ben77650 Membre
    avril 2014 modifié #4

    @colas: Merci effectivement déjà  c'était une erreur que je n'avais pas vu, mais avant ça marchais, la cela crashe complétement


     


    @Larme: re, la présentation c'est bon c'est ok


     


    Quand je fais 



    NSLog(@test: %@",[[[strResult  objectForKey:@titre]objectAtIndex:cpt] objectForKey:@titre]);

    Ca ne s'affiche pas


     


    Merci en tout cas à  vous 2 d'essayer de m'aider


  • LarmeLarme Membre
    avril 2014 modifié #5

    Tu pourrais nous montrer NSLog(@strResult: %@", strResult);?

    Tout du moins les clés que tu utilises, et mettre XxX ou autre truc bidon en valeur.


    Ah, et merci d'utiliser la balise code.


  • Ben77650Ben77650 Membre
    avril 2014 modifié #6

    Je l'avais fait sur SO ;)



    strResult:{
    cat = 46;
    id = 1496;
    }
  • LarmeLarme Membre
    avril 2014 modifié #7

    Oui, mais là , je ne vois pas d'itération possible en fait.


    Et quand tu dis que cela ne s'affiche pas, tu veux dire que tu as "test: null" ou rien du tout ? Si tu n'as rien du tout, c'est que cela ne passe pas dans ta boucle. Auquel cas, comme je l'ai dis juste avant, je ne vois pas d'itération à  faire. Enfin, je ne sais pas à  quel moment/quel niveau la faire.


  • Ben77650Ben77650 Membre
    avril 2014 modifié #8

    Je veut dire que j'ai absolument rien du tout, après c'est peut être normal qu'il rentre pas dans la condition, vu que cpt n'est jamais supérieur a 20 ([strResult count]).


     


    Après si je met <20 (et non >20), il me quitte l'application brutalement en me disant


     



    2014-04-17 12:00:39.182 Appli[1468:60b] -[__NSCFArray objectForKey:]: unrecognized selector sent to instance 0x8f14370


    2014-04-17 12:00:39.183 Appli[1468:60b] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSCFArray objectForKey:]: unrecognized selector sent to instance 0x8f14370'


    *** First throw call stack:


    (


    0   CoreFoundation                      0x01ba91e4 __exceptionPreprocess + 180


    1   libobjc.A.dylib                     0x019288e5 objc_exception_throw + 44


    2   CoreFoundation                      0x01c46243 -[NSObject(NSObject) doesNotRecognizeSelector:] + 275


    3   CoreFoundation                      0x01b9950b ___forwarding___ + 1019


    4   CoreFoundation                      0x01b990ee _CF_forwarding_prep_0 + 14


    5   Appli                        0x0000e81d __29-[OffreViewController getAll]_block_invoke_2 + 477


    6   libdispatch.dylib                   0x01fa67b8 _dispatch_call_block_and_release + 15


    7   libdispatch.dylib                   0x01fbb4d0 _dispatch_client_callout + 14


    8   libdispatch.dylib                   0x01fa9726 _dispatch_main_queue_callback_4CF + 340


    9   CoreFoundation                      0x01c0e43e __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ + 14


    10  CoreFoundation                      0x01b4f5cb __CFRunLoopRun + 1963


    11  CoreFoundation                      0x01b4e9d3 CFRunLoopRunSpecific + 467


    12  CoreFoundation                      0x01b4e7eb CFRunLoopRunInMode + 123


    13  GraphicsServices                    0x03a5b5ee GSEventRunModal + 192


    14  GraphicsServices                    0x03a5b42b GSEventRun + 104


    15  UIKit                               0x005e8f9b UIApplicationMain + 1225


    16  Appli                        0x0001e79d main + 141


    17  libdyld.dylib                       0x021f0701 start + 1


    )


    libc++abi.dylib: terminating with uncaught exception of type NSException


    (lldb) 


     



  • Tu fais un objectForKey: (truc typique NSDictionary) sur un NSArray.

    Donc ça plante.


    Pour moi, je pense que tu n'as pas compris comment est structuré ton JSON.


  • Bah j'ai bien compris que ma variable strResult était de type id.


     


    Après c'est vrai que si tu as quelques explications je suis preneur, comme je l'ai dit je débute, donc de l'aide ne serait pas de refus.


  • Tu utilises simultanément



    [strResult objectAtIndex:0]

    et 



    [strResult  objectForKey:@categorie]

    Donc, faut savoir ! C'est un NSArray ou un NSDictionary !!!


     


    Le type de ton objet est celui retourné par la méthode [NSJSONSerialization JSONObjectWithData:result options:0 error:&error];


     


    Dire que c'est un id ne veut pas dire que ton objet n'a pas de type.


    Cela veut juste dire que le compilateur ne sait pas quel est son type.


  • LarmeLarme Membre
    avril 2014 modifié #12

    • dico = {


    cle1 = valD1,


    cle2 = valD2,


    }


    => NSDictionnary, récupération de valD1 via [dico objectForKey:@cle1]


    valD2 = [dico objectForKey:@cle2];


     


    • array = (


    valA1,


    vaA2,


    )


    => NSArray, récupération de valA1 par [array objectAtIndex:0].
    valA2 = [array objectAtIndex:1];


    • Maintenant, tu peux avoir des Dictionnaires dans un Array (exemple valD1 est un array, des Arrays dans des Dictionnaires (exemple valA2 est un dictionnaire).

    Quand on ne maà®trise pas, il faut y aller petit à  petit.

    Tu auras peut-être besoin de caster : NSDictionary *valD1 = (NSDictionary *)[dico objectForKey:@cle1].

    Donc je te conseille d'utiliser des valeurs temp, de regarder niveau par niveau, de ne pas hésiter à  les Logs. Regarde donc ce qui est au premier niveau de strResult. Etc.


  • Ben77650Ben77650 Membre
    avril 2014 modifié #13

    Pour faire claire concernant ce que me renvoie strResult:



    strResult: (
            {
            CodePostal = 31400;
            cat = 46;
            categorie = "V\U00e9h citadines/compactes/berlines";
            date = "17-04-2014";
            departement = 63;
            description = "Kia Pro_cee'd CRDI 115 SPORT berline, pewter beige, 6 cv, 3 portes, mise en circulation le 06/04/2010.
    \nPhoto sur demande.";
            enLigne = "<null>";
            id = 1496;
            prix = 12000;
            region = "Midi-Pyr\U00e9n\U00e9es";
            srcImage = "";
            status = 1;
            tel = xxxxx;
            "tel_cache" = Y;
            titre = "Kia Pro_cee'd CRDI 115 SPORT";
            user = kia;
            ville = "Toulouse, France";
        },
            {
            CodePostal = 75012;
            cat = 46;
            categorie = "V\U00e9h citadines/compactes/berlines";
            date = "16-04-2014";
            departement = 41;
            description = " je mes mon espace 3 2.2 dt (moteur tr\U00e8s robuste ) a vendre ; 2 eme main ;bien entretenu 
    \nsupport moteur +croie d'alternateur + tendeur+4 bougie pr\U00e9chauffage+batterie +plaquette de frein (moins de 3 mois) 
    \noptions: 7 places avec 7 si\U00e8ges 
    \n2.2 dt moteur increvable 
    \nclim charger
    \naccoudoir
    \ndouble toit ouvrant 
    \nlunette arri\U00e8re ouvrante 
    \njante alu
    \nchargeur cd 6 avec sa t\U00e9l\U00e9commande d'origine 
    \nporte bagage 
    \nbarre de l'attelage 
    \npropre int\U00e9rieur et ext\U00e9rieur par apport a son age
    \nou \U00e9change contre une petite voiture diesel car j en ai plus besoin maintenant d'une grande voiture";
            enLigne = "<null>";
            id = 1495;
            prix = 2700;
            region = "Ile-de-France";
            srcImage = "2014/04/16/28ens936z2.jpg";
            status = 1;
            tel = xxxx;
            "tel_cache" = Y;
            titre = "Espace 3 2.2 dt";
            user = bou;
            ville = "Paris, France";
        },

    Sinon du coup quelqu'un sait il me dire pourquoi ça plante quand je fais 



    for(int cpt=0; cpt>[strResult count];cpt++)

    J'avoue ne pas comprendre car quand je fais 



    NSLog(@%ld,(unsigned long)[strResult count]);

    il m'affiche bel et bien 20


  • LarmeLarme Membre
    avril 2014 modifié #14
    cpt< [strResult count] déjà .

    Sinon, normalement, cela devrait marcher :
     


    for (int i = 0; i < [strResult count]; i ++)
    {
      NSDictionary *dicoTemp = [strResult objectAtIndex:i];
      NSString *city = [dicoTemp objectForKey:@ville];
    }
    ou
    for (NSDictionary *aDico in strResult)
    {
      NSString *city = [aDico objectForKey:@ville];
    }
    Tu vois, que déjà , lorsque tu avais écrit la première fois à  quoi ressemblait ton strResult, moi, j'y voyais un dictionnaire. Alors qu'en réalité, c'est un array de dictionnaires.
  • Ben77650Ben77650 Membre
    avril 2014 modifié #15

    Bon effectivement ça fonctionne ainsi (1ere option), donc c'est une bonne chose, et une sacrée avancée.


     


    J'aimerais ajouter toutes les infos dans un NSMutableArray et pourra le renvoyer à  la fin donc saurais tu m'éclairer sur la manière de faire s'il te plait ?


  • C'est étrange de ranger ça dans un NSArray (j'ai cru comprendre de ton code que tu veux un NSArray de NSArray) plutôt que de garder une forme telle quelle : NSArray de NSDictionary. Disons que de mon point de vue externe, ce n'est pas pertinent.


    Du coup, en reprenant ton code :



    NSArray *arrayTemp = [aDico allValues];
    [liste addObject:arrayTemp];

    Par contre, l'ordre n'est pas définit (cf. doc sur allValues). Je ne suis pas sûr qu'ils soient tous dans le même ordre, ou dans l'ordre que tu souhaites...

    Je ne sais pas si tu comptes garder toutes les données, mais si tu veux garder un certain ordre :



    NSMutableArray *arrayTemp = [[NSMutableArray alloc] init];
    [arrayTemp addObject:[aDico objectForKey:@ville]]; //etc.
    [liste addObject:arrayTemps];
  • Ben77650Ben77650 Membre
    avril 2014 modifié #17

    Bah à  vrai dire le tableau (au lieu du dictionnaire) je pense que c'est la solution la plus simple (enfin celle que je maitrise le mieux) après si le dictionnary est plus simple d'utilisation et mieux pourquoi pas changer, comme on dit il y a que les imbéciles qui changent pas d'avis ^^


     


    A vrai dire je ne veut pas garder toutes les infos récupérées, je veut juste sur mon écran actuel en afficher 6 d'entre elles (titre, srcImage, date, prix, ville, catégorie)


     


    Le souci c'est que liste



    NSMutableArray* liste;
    NSMutableArray* arrayTemp = [[NSMutableArray alloc]init];
        
    for(cpt=0; cpt<[strResult count];cpt++)
                {
                    [liste addObject:[[NSMutableArray alloc]init]];
                    
                    NSDictionary *dicoTemp = [strResult objectAtIndex:cpt];
                    
                    [arrayTemp addObject:[dicoTemp objectForKey:@ville]];
                    [liste addObject:arrayTemp];
                }

    quand je fais un Log à  la fin avant de le retourner, ça me renvoie toujours null :/


     


    Et quand je met



    NSMutableArray* liste= [[NSMutableArray alloc]init];
    NSMutableArray* arrayTemp = [[NSMutableArray alloc]init];
        
    for(cpt=0; cpt<[strResult count];cpt++)
                {
                    
                    NSDictionary *dicoTemp = [strResult objectAtIndex:cpt];
                    
                    [arrayTemp addObject:[dicoTemp objectForKey:@ville]];
                    [liste addObject:arrayTemp];
                }

    voila mon retour: liste: (


    )


  • Ton soucis vient du fait que tu fais de l'asynchrone.

    En bref, normalement, les actions s'enchaà®nent une fois que la précédente est terminée. Ce n'est pas le cas ici (async).

    Du coup, tu lui dis : Récupère les données et parses-les pendant ce temps-là , et l'appel du NSLog de liste arrive avant que cela ne soit fait.

     


  • Ben77650Ben77650 Membre
    avril 2014 modifié #19

    Bah voila la fonction complète:



    -(NSMutableArray*)getAll{
        NSMutableArray* liste = [[NSMutableArray alloc]init];
        NSMutableArray* arrayTemp = [[NSMutableArray alloc]init];
        
        dispatch_queue_t downloadQueue = dispatch_queue_create("Get All Offers", NULL);
        
        dispatch_async(downloadQueue, ^{
            NSData *result = [self executePostCall];
            dispatch_async(dispatch_get_main_queue(), ^{
                
                id strResult=nil;
                int cpt;
                NSError* error;
                strResult = [NSJSONSerialization JSONObjectWithData:result options:0 error:&error];
                
                for(cpt=0; cpt<[strResult count];cpt++)
                {
                    
                    NSDictionary *dicoTemp = [strResult objectAtIndex:cpt];
                    
                    [arrayTemp addObject:[dicoTemp objectForKey:@titre]];
                    [arrayTemp addObject:[dicoTemp objectForKey:@srcImage]];
                    [arrayTemp addObject:[dicoTemp objectForKey:@date]];
                    [arrayTemp addObject:[dicoTemp objectForKey:@prix]];
                    [arrayTemp addObject:[dicoTemp objectForKey:@ville]];
                    [arrayTemp addObject:[dicoTemp objectForKey:@categorie]];
                    [liste addObject:arrayTemp];
                }
                
                
            });
        });
         NSLog(@liste: %@",liste);
        return liste;
    }

    Je ne vois pas ou mettre ailleurs les 2 dernières lignes, car sinon ça me met une erreur.


  • colas_colas_ Membre
    avril 2014 modifié #20

    Je ne vois pas où ça bugue, mais tu as oublié de réinitialiser ton arrayTemp.


     


    Fais plutôt



    -(NSMutableArray*)getAll{
        NSMutableArray* liste = [[NSMutableArray alloc]init];
        
        dispatch_queue_t downloadQueue = dispatch_queue_create("Get All Offers", NULL);
        
        dispatch_async(downloadQueue, ^{
            NSData *result = [self executePostCall];
            dispatch_async(dispatch_get_main_queue(), ^{
                
                id strResult=nil;
                int cpt;
                NSError* error;
                strResult = [NSJSONSerialization JSONObjectWithData:result options:0 error:&error];
                
                for(cpt=0; cpt<[strResult count];cpt++)
                {
                    
                    NSDictionary *dicoTemp = [strResult objectAtIndex:cpt];
                    NSMutableArray* arrayTemp = [[NSMutableArray alloc]init];
        //etc.

  • Ben77650Ben77650 Membre
    avril 2014 modifié #21

    Ok merci cela règle un problème que j'avais (il m'affichais 3 offres à  20 reprises)


     


    Merci à  ceux qui m'ont aidés (Larme et colas2)


Connectez-vous ou Inscrivez-vous pour répondre.