GeckoGeek.fr

Paradigme d'un lézard

Dimanche 23 Juillet 2017

JSON sur iPhone : installation et exemple

Par Vinz le 03/01/2010 dans Apple, Programmation | 31 commentaires

Nous allons expliquer par ce billet comment lire du code JSON sous iPhone tout en gérant d’éventuelles erreurs. Nous ne ferons que présenter la librairie avec un exemple clair et concis qui peut facilement se customiser selon les besoins.

MAJ 3 Octobre 2010 : Modifications effectuées pour supporter la 2.3.1 de la librairie utilisée.

Pourquoi du JSON ?

Même si à l’heure actuelle les réseaux mobiles ne sont pas encore trop saturés en France (contrairement à nos amis Anglophones), il est bon de choisir un moyen relativement léger pour faire transiter des données. Le XML, quand bien même très répandu et facile à utiliser, n’est pas forcément très léger. Voici un rapide exemple pour le prouver (sans en-tête de charset etc).

Version XML

<bakery>
  <name>Au petit Gecko</name>
  <adress>10 Rue du Soleil, Mer du Paradis</adress>
  <candies>
    <candy>
      <name>La Spéciale</name>
      <price>0.45</price>
    </candy>
    <candy>
      <name>Gourmandise du Gecko</name>
      <price>0.30</price>
    </candy>
  </candies>
</bakery>

Version JSON

{ "bakery":
  {
    "name": "Au petit Gecko",
    "adress": "10 Rue du Soleil, Mer du Paradis",
    "candies": {
      "candy": [
        {"name": "La Spéciale", "price": "0.45"},
        {"name": "Gourmandise du Gecko", "price": "0.30"}
      ]
    }
  }
}

Quelques statistiques

Comme on peut le voir, le JSON est bien plus compact. On aurait pu réduire un peu plus le XML en mettant plus d’attributs dans les éléments, mais c’est selon les cas. Nous obtenons 311 caractères pour le XML contre 268 caractères pour le JSON. Soit un gain de d’environ 14%. Notre exemple n’a qu’une valeur modérée puisqu’il n’y a que quelques lignes. Toutefois si nous venions à rajouter 100 bonbons (au lieu de 2 actuellement), nous aurions un gain d’environ 35/40%. Donc selon les données le gain est plus ou moins fort et surement non-négligeable lorsqu’il s’agit d’une connexion à faible débit ou s’il faut transférer beaucoup de données.
Toutefois nous ne prenons pas tout en compte, nous pourrions aussi venir à comparer le temps de parsing. Mais ce n’est pas le but ici, donc nous passerons sur ce coup-là :-]

Installer JSON pour iPhone

Télécharger le projet

Avant de pouvoir utiliser du JSON sur iPhone il vous faut d’abord télécharger la librairie qui pourra l’analyser. Allez sur le projet GitHub à cette adresse et téléchargez le dernier zip||dmg. Cela a changé puisqu’avant le projet était hébergé sur Google Code. A l’heure de la modification de ce tutorial, la version téléchargée est la 2.3.1.

L’ajouter au projet xCode

Décompressez l’archive et ajoutez le dossier “Classes” à votre projet xCode. Vous devriez même faire une copie du dossier Classes sur votre bureau, le renommer en “json” (ou autre), puis le déplacer dans vos sources (sans oublier de cocher la case pour que xCode copie les fichiers dans votre projet). Puis il vous suffit de lier la librairie à votre projet avec un :

#import "JSON.h"

Exemple JSON

Nous partons du principe que vous avez récupéré le code JSON via une requête HTTP (nous ferons bientôt un billet à ce propos) ou bien dans un fichier.

Etape par étape

Dans un premier temps nous déclarons les variables utilisées :

// Vars
SBJsonParser *json;
NSError *jsonError;
NSDictionary *jsonResults;
NSString *response;
  • La première variable (json) permet de procéder au traitement de la chaîne de texte contenant le code JSON.
  • La deuxième (jsonError) est utilisée pour stocker une éventuelle erreur lors se la procédure.
  • La troisième (jsonResults) contient la liste des objets après le traitement
  • Et enfin la dernière (response) contient votre code à parser. Ici nous reprendrons celui précisé en haut.

Puis nous initialisons la variable json :

response = @"{\"bakery\":{\"name\":\"AupetitGecko\",\"adress\":\"10RueduSoleil,MerduParadis\",\"candies\":{\"candy\":[{\"name\":\"LaSpéciale\",\"price\":\"0.45\"},{\"name\":\"GourmandiseduGecko\",\"price\":\"0.30\"}]}}}";

// Init JSON
json = [ [ SBJsonParser new ] autorelease ];

Et enfin nous procédons à la lecture de la variable contenant le code JSON (response) :

// Get result in a NSDictionary
jsonResults = [ json objectWithString:response error:&jsonError ];

Si une erreur est survenue alors la variable jsonResults sera à “nil”. Il nous suffit alors de procéder ainsi :

// Check if there is an error
if (jsonResults == nil) {

	NSLog(@"Erreur lors de la lecture du code JSON (%@).", [ jsonError localizedDescription ]);

} else {

	// Do some stuff

}

Il ne nous reste plus qu’à parser le code JSON (voir l’exemple ci-dessus) :

// Check if there is an error
if (jsonResults == nil) {

	NSLog(@"Erreur lors de la lecture du code JSON (%@).", [ jsonError localizedDescription ]);

} else {

	NSArray *candiesList;
	NSDictionary *bakery = [ jsonResults objectForKey:@"bakery" ];
	NSLog(@"Nom : %@", [ bakery objectForKey:@"name" ]);
	NSLog(@"Adresse : %@", [ bakery objectForKey:@"adress" ]);
	NSLog(@"Bonbons :");
	candiesList = [ [ bakery objectForKey:@"candies" ] objectForKey:@"candy" ];
	for (NSDictionary *candy in candiesList) {

		NSLog(@"\tNom=%@ et Prix=%@", [ candy objectForKey:@"name" ],
							[ candy objectForKey:@"price" ]);

	}

}

Notez que nous avons ici stocké l’ensemble des bonbons dans un NSArray et non un NSDictionnary. Le NSArray contient bien au final un ensemble de NSDictionnary que l’on peut parcourir sans problème.

Tout le code

Et pour finir l’ensemble des morceaux assemblés bout à bout :

// Vars
SBJsonParser *json;
NSError *jsonError;
NSDictionary *jsonResults;

response = @"{\"bakery\":{\"name\":\"AupetitGecko\",\"adress\":\"10RueduSoleil,MerduParadis\",\"candies\":{\"candy\":[{\"name\":\"LaSpéciale\",\"price\":\"0.45\"},{\"name\":\"GourmandiseduGecko\",\"price\":\"0.30\"}]}}}";

// Init JSON
json = [ [ SBJsonParser new ] autorelease ];

// Get result in a NSDictionary
jsonResults = [ json objectWithString:response error:&jsonError ];

// Check if there is an error
if (jsonResults == nil) {

	NSLog(@"Erreur lors de la lecture du code JSON (%@).", [ jsonError localizedDescription ]);

} else {

	NSArray *candiesList;
	NSDictionary *bakery = [ jsonResults objectForKey:@"bakery" ];
	NSLog(@"Nom : %@", [ bakery objectForKey:@"name" ]);
	NSLog(@"Adresse : %@", [ bakery objectForKey:@"adress" ]);
	NSLog(@"Bonbons :");
	candiesList = [ [ bakery objectForKey:@"candies" ] objectForKey:@"candy" ];
	for (NSDictionary *candy in candiesList) {

		NSLog(@"\tNom=%@ et Prix=%@", [ candy objectForKey:@"name" ],
							[ candy objectForKey:@"price" ]);

	}

}

Si ce tutorial vous a été utile ou si vous avez besoin d’une autre information sur le sujet, n’hésitez pas à laisser un commentaire :-]

Commentaires (31)
  1. Danny le 22 Jan 2010 à 13:09

    Merci pour ce tuto. Je débute et c’est très utile.
    Comment faire pour recuperer un JSON sur un serveur externe (HttpXMLRequest?)?

    Merci.

  2. Vinz le 22 Jan 2010 à 13:29

    Hello !
    Bien si ca t’a été utile :-)
    Alors pour le serveur, soit tu passes par le frameworks d’Apple (mais j’y ai pas encore beaucoup touché), soit tu passes par une lib gratuite sympa : ASIHTTPRequest (premier lien sur google).
    Je ferai à l’occasion un tuto à ce propos ^^ mais sur le site officiel tu trouveras des tuto pour recevoir des données facilement !
    @+

  3. rim le 7 Apr 2010 à 10:04

    it was so helpful
    thx a lot :)

  4. Vinz le 7 Apr 2010 à 18:53

    Happy it was helpful :-) sorry for the french. Maybe one day we will do an english version of some articles ^^

  5. rim le 12 Apr 2010 à 15:51

    non, il était intréssant pour moi c parce que il était rédigé en francais ..

    Vinz, avez vous un lien pour la source code de ce petit exemple

    j’arrive pas à le compiler correctement
    …je sais pas exactement comment parser un un autre web service de format JSON

  6. Vinz le 12 Apr 2010 à 18:06

    Hello
    Héhé, ok :-)
    Mmm je vais essayer aujourd’hui ou demain de faire un projet xCode avec ce Hello World :-) (et corrigerai l’erreur si j’en ai glissé une ^^) Je te préviens par mail quand je l’ai fait 😉
    Sinon tu entends quoi par ta dernière remarque ? si tu as un exemple de code jSon à parser montre moi.
    A+
    Vinz

  7. rim le 13 Apr 2010 à 09:26

    j’attends encore ton hello world project …

  8. rim le 13 Apr 2010 à 09:28

    concerant ce code, d’ou tu as récupéré l’information (le fichier .json)

    normalement, il ya une phase qui manque, celle de la récupération du web service
    J’ai aimé testé ton code chez moi, mais j’ai pas pu ..

  9. Vinz le 13 Apr 2010 à 14:35

    Dès que j’ai le temps de le faire…
    Sinon si tu lisas les commentaires plus haut, tu verrai qu’une autre personne a posé la même question et que j’ai répondu. Ce tuto parle juste du parsing en JSON avec iPhone, et non de la récupération du code qui est une chose tout autre et demande un autre tutorial pour bien l’expliquer.

  10. rim le 13 Apr 2010 à 17:30

    peux tu me l’expliquer ? j’en ai besoin

  11. Vinz le 13 Apr 2010 à 21:28

    Hummm de manière courte je te conseille d’utiliser la librairie ASIHTTPRequest qui facilite les relations avec le serveur. Tu as des exemples sur le site pour faire un Hello World à ce niveau. Puis tu récupères le code JSON via serveur grâce à ça, et tu le parses avec notre tuto 😉

  12. Videos le 24 Apr 2010 à 15:39

    Super ce tuto, je vais utiliser tout ça pour mettre au point ma première appli iPhone. :)
    Merci Vinz 😉

  13. Predict le 29 Apr 2010 à 12:22

    merci beaucoup pour ce tutoriel, j’ai cependant deux petites questions.

    Je ne comprends pas très bien cette ligne:
    for (NSDictionary *candy in candiesList) {

    même si j’ai pu constater que ça marche très bien, je ne comprends pas ce qui fait que dans la boucle for, on passe d’un élément de la liste à un autre. Je ne comprends pas non plus pourquoi candiesList est faite de dictionnary et pas de string.
    merci.

  14. Vinz le 29 Apr 2010 à 13:02

    Hello !
    Alors alors :
    – En fait on passe d’un élèment à un autre car c’est le for( … in … ) qui fait ça. Y’a la même chose dans d’autres langages comme en PHP avec “foreach()”. L’idée est de boucler sur chaque élèment de la liste. En français cela donnerait : PourChaque( bonbon dans listBonbons ), tu vois le genre ?
    – candiesList est un NSArray car c’est un tableau d’élèments (qui sont des bonbons). Le NSDictionary est le “candy” (donc l’élèment) car il ne contient pas que une valeur, mais plusieurs trucs. C’est un objet, donc il peut contenir un nom, une valeur etc Ici candy contient “name” et “price”. Tu vois un peu mieux ?
    N’hésite pas si je n’ai pas été assez clair sur un point.

    A+ !
    Vinz

  15. Rom le 20 May 2010 à 18:29

    Hello!

    Très bon post.
    Actuellement en école d’ingé, je bosse sur un projet où je developpe une application iPhone (pour la pedagogie, sans finalité) qui est un gestionnaire de coupons de reductions, et dans l’idéal ces derniers sont contenus dans une base de données.

    Par contre, serait-il possible de détailler ou de m’indiquer un lien qui explique la requete HTTP?

    merci!

  16. Vinz le 20 May 2010 à 18:35

    Hello !

    Merci 😉
    Ca semble vraiment devenir urgent qu’on fasse un petit billet pour les req http on dirait ^^
    Le plus simple en attendant un tuto, je te conseille d’ajouter la librairie dont j’ai parlé plus haut et surtout de lire (pas forcément entièrement) leur page d’exemples : http://allseeing-i.com/ASIHTTPRequest/How-to-use
    Voilà pour toute question plus précises faut pas hésiter ^^

    A+
    Vinz

  17. ArtOflex le 2 Oct 2010 à 17:08

    Bonjour, j’ai parcouru votre tuto et je crois qu’il faudrait le mettre à jour car le Github de la Lib JSon à changer, ensuite quand on décompresse l’archive ca ne ressemble plus à la structure du tuto (genre le dossier JSON n’existe plus…) bref je suis bien embêter car j’aurais aimer faire le tuto !!!

  18. Vinz le 3 Oct 2010 à 10:44

    Ok on va jeter un coup d’oeil, merci d’avoir prévenu 😉

  19. Vinz le 3 Oct 2010 à 11:11

    Voilà on a fait les modifications necessaire, cela devrait mieux marcher maintenant ^^

  20. ArtOflex le 4 Oct 2010 à 13:06

    Merci pour ta réactivité, allez je me lance !!! yeahhh 😉

  21. Hitch le 28 Dec 2010 à 02:16

    Bonjour l’équipe!
    Voila je suis un étudiant en informatique,et on nous a donnée un projet sur une application iPhone. On est entrain de faire une application sur la gestion des produits ecolos. Donc ceci dit que notre appli doit avoir une grande base données.Malgré tout ça, je n’ai aucune idée de comment procédé s’il est possible de créer une base de données en interne de l’appli ou en externe. Alors j’attends, vos conseils, et tout ce qui peut m’aidé sur ce projet. Je vous remercie d’avance de votre aide.
    Cordialement

  22. Vinz le 29 Dec 2010 à 01:06

    Hello !
    Cela dépend de tes données. Est-ce qu’elles ont besoin d’être mises à jour ou non ? Si oui, alors une BDD externe (sur serveur distant) c’est mieux. Sinon en interne, sur iPhone, est suffisant. Prendre en compte aussi que c’est pour un projet (donc bdd externe pas forcément necessaire ?) et aussi la taille de la BDD.
    Disons que si c’est pour un projet étudiant, une BDD interne devrait suffire. Deux possibilités : fichiers “xml” en .plist, ou bien BDD type sqlite. Je pense que les fichiers en .plist devraient être suffisant, c’est facile à parser avec les API d’Apple. Faite des recherches à ce niveau 😉
    A+

  23. Maxime le 28 Apr 2011 à 22:03

    Wow! merci pour le tuto! en français en plus! :)

  24. Queen le 26 May 2011 à 18:00

    Salut Vinz,

    Je voudrais manipuler des données sur iphone, en local; tout en laissant la possibilité de faire évoluer plus tard et de travailler à distance. Que me conseillez vous:
    – utiliser des fichier xml,
    – utiliser json,
    – ou sgl light?

    Merci

  25. Queen le 26 May 2011 à 18:02

    sql :)

  26. Vinz le 26 May 2011 à 22:14

    Hello Queen,

    Pas très bien comprit la question ^^
    L’idée c’est quoi ? de manipuler des données sur l’iPhone dont la structure pourrait changer au cours du temps, et en parallèle de pouvoir faire des requêtes serveurs ?
    Enfin si on reprend le problème de manière générale, quelque soit la question, le choix XML (.plist) ou JSON ou SQL ne tient qu’à toi et des requêtes que tu voudras faire… Avec SQL Light tu peux directement faire des requêtes sympas. Si ton fichier est stocké en JSON, tu peux le parser mais après il faut te débrouiller.

    Quoiqu’il en soit si tu fais évoluer la structure de tes données, il suffit d’avoir des méthodes de migration qui checkent la version actuelle de ta base et puis en fonction de cette dernière font évoluer la structure vers la version la plus récente.

    Donc peux-tu préciser ce que tu souhaites faire ^^? avec un exemple si possible.

    A+

  27. JarJar le 21 Jun 2011 à 20:47

    Excellent

  28. Djoko le 30 Sep 2011 à 15:08

    Salut,

    Super tuto. Mais je suis face à un problème que je ne parviens pas à résoudre. J’ai récupéré un NSDictionnary à partir du JSON suivant
    {
    ………”Bourbon”:139,
    ………”Mousse”:[“1″],
    ………”Recale_a_l_entree”:null
    }
    Les points sont là pour l’indentation :D. Mon problème est que je ne parviens pas à tester si Recal_a_l_entree est null. Je sais bien qu’un null en Objectiv C est un nil, mais visibleme,t if(Recale_a_l_entree == nil) ne fonctionne pas et naturellement, null n’est absolument pas reconnu comme la string “null”.

    Merci

  29. Djoko le 30 Sep 2011 à 15:38

    J’ai trouvé. il faut faire

    if(Recale_a_l_entree isEqual:[NSNull null]])

    Vous pensez bien que Recale_a_l_entree est plutôt de la forme [NSDictionnary objectforKey@”Recale_a_l_entree”], mais vous aviez compris ? 😉

    + Et bon tuto !

  30. Vinz le 1 Oct 2011 à 09:54

    Salut ! désolé pour le temps de réponse. Alors effectivement le nil ici servirait si le champ n’existe pas du tout. Ici dans ce cas il y a marqué null (à cause de PHP ^^), du coup il faut faire comme tu as marqué, et le comparer à NSNull ^^
    Moi je te conseillerai plutôt de ne pas renvoyer le champ via PHP et de comparer avec nil. Par ailleurs pour une double sécurité, tu peux vérifier plutôt la class de ton champ. Par exemple si Recale_a_l_entree devait être un NSString, tu pourrais faire if (Recale_a_l_entree != nil && [ Recale_a_l_entree isKindOfClass[ NSString class ] ]). Bonne continuation 😉

  31. Djoko le 21 Nov 2011 à 19:40

    Salut,

    Merci pour ta réponse. La partie serveur ne dépend en fait pas de moi (ce qui ne facilite pas les choses non plus :D). Je prend note de la suite.

    Djoko


Laisser un commentaire