Développer des Apps iOS 8 avec Swift

Partie 2 : Affichage des résultats d'une requête

Jameson Quave

Traducteur

Mishulyna

Cette section a été entièrement mise à jour pour refléter les changements dans Xcode 6.3, à partir du 16 avril 2015.

Dans la partie 1, nous avons vu quelques notions de base de Swift et avons mis en place un exemple de projet simple qui crée une Table View et y met un peu de texte. Si vous ne l'avez pas encore lue, vous pouvez le faire ici.

Pour cette section, nous allons faire quelque chose d'un peu plus ambitieux.

Les commentaires et les suggestions d'amélioration sont les bienvenus, alors, après votre lecture, n'hésitez pas. Commentez .

Retrouvez toute la série "Développer des Apps iOS 8 avec Swift"

Aller à la partie 1 maintenant ->

- Titre : Développer des Apps iOS 8 avec Swift

- Auteur : Jameson Quave

- Traducteur : Mishulyna

- Parution : 18 septembre 2014

- Mise à jour : 6 janvier 2016

- Public visé :

- Licence : Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright ® 2014 Jameson Quave - Developpez. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.

Voir également :

- Partie 1 : introduction - application basique Hello World

- Partie 3 : les bonnes pratiques

- Partie 4 : ajouter les interactions

- Partie 5 : chargement asynchrone d'images et mise en cache

- Partie 6 : interaction avec des vues multiples

- Partie 7 : animations, audio et cellules Table View personnalisées

- Apprendre Swift à partir d'Objective-C

- Comprendre les optionnelles : quand et comment les utiliser ?

Sommaire

- Introduction

- I. Connecter l'interface utilisateur

- II. Interroger l'API

- III. Appeler l'API

- IV. Recevoir la réponse

- V. Mettre à jour la Table View sur l'interface utilisateur

- VI. Code source

- VII. Vous avez une question ou un problème ?

- VIII. Remerciements Developpez

Introduction

Dans la partie 1, nous avons vu quelques notions de base de Swift et avons mis en place un exemple de projet simple qui crée une Table View et y met un peu de texte. Si vous ne l'avez pas encore lue, vous pouvez le faire ici. Si vous aimez ces tutoriels, sachez que je travaille aussi sur un livre avec un contenu de qualité pour les développeurs Swift, et il est disponible en précommande dès maintenant.

Pour cette section, nous allons faire quelque chose d'un peu plus ambitieux. Nous allons envoyer une requête à l'API de recherche iTunes pour iTunes Store, télécharger les résultats JSON, les parser en des dictionnaires et puis remplir notre Table View avec ces informations. Ensuite, nous allons ajouter une interaction de l'utilisateur, c'est-à-dire un événement de clic à la tableview, de sorte que lorsqu'un élément est cliqué, iTunes Store sera ouvert.

Si cela vous semble être beaucoup de travail, ne vous inquiétez pas. C'est une fonctionnalité assez basique pour les applications iOS et c'est l'une des choses les plus communes que tout développeur doit faire. Allons-y…

I - Connecter l'interface utilisateur

La première chose que nous devons faire est d'obtenir une référence vers notre tableview, afin qu'elle puisse être utilisée à partir du code. Pour ce faire, ajoutez cette ligne à votre fichier ViewController.swift, juste en dessous de la définition de la classe, mais en dehors de toute fonction :

1. @IBOutlet var appsTableView : UITableView!

Cette ligne de code permet de relier la Table View de notre storyboard à la variable appsTableView. Enregistrez le fichier et ouvrez votre storyboard. Maintenant, sélectionnez l'objet View Controller (celui avec une icône jaune) et dans le volet de droite cliquez sur le dernier onglet, Connections Inspector. Vous devriez maintenant voir une sortie pour appsTableView. Cliquez et faites glisser à partir du point à côté de cette sortie vers la Table View dans notre scène.

Ajoutez également une variable pour contenir les données de la table, juste en dessous de la définition de la classe ViewController :

1. var tableData = []

II - Interroger l'API

Maintenant que nous avons connecté l'IU, nous sommes prêts à appeler l'API. Créez une nouvelle fonction appelée searchItunesFor(searchTerm: String). Nous allons l'utiliser pour exécuter des requêtes sur des termes arbitraires.

Pour garder ce tutoriel court, je vais simplement poster mon code final et laisser les commentaires se charger d'une partie de l'explication. Je suis toujours ouvert aux questions et à d'autres discussions, donc n'hésitez pas à intervenir !

1. func searchItunesFor(searchTerm: String) {

2. // L'API iTunes demande des termes multiples, séparés par des + , alors remplacez les espaces par des +

3. let itunesSearchTerm = searchTerm.stringByReplacingOccurrencesOfString(" ", withString: "+", options: NSStringCompareOptions.CaseInsensitiveSearch, range: nil)

5. // Maintenant échappez tout ce qui n'est pas URL-friendly

6. if let escapedSearchTerm = itunesSearchTerm.stringByAddingPercentEscapesUsingEncoding(NSUTF8StringEncoding)   {

7. let urlPath = "https://itunes.apple.com/search?term=\(escapedSearchTerm)&media=software"

8. let url = NSURL(string: urlPath)

9. let session = NSURLSession.sharedSession()

10. let task = session.dataTaskWithURL(url!, completionHandler: {data, response, error -> Void in

11. println("Tâche teminée")

12. if(error != nil) {

13. // Si une erreur survient lors de la requête web, l'afficher en console

14. println(error.localizedDescription)

15. }

16. var err: NSError?

17. if let jsonResult = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers, error: &err) as? NSDictionary {

18. if(err != nil) {

19. // Si une erreur survient pendant l'analyse du JSON, l'afficher en console

20. println("Erreur JSON \(err!.localizedDescription)")

21. }

22. if let results: NSArray = jsonResult["results"] as? NSArray {

23. dispatch_async(dispatch_get_main_queue(), {

24. self.tableData = results

25. self.appsTableView!.reloadData()

26. })

27. }

28. }

29. })

31. // task est juste un objet avec toutes ces propriétés définies

32. // Afin d'exécuter réellement la requête web, nous devons appeler resume()

33. task.resume()

34. }

35. }

Allons-y ligne par ligne.

Tout d'abord, nous avons besoin de faire quelques adaptations des termes de recherche que nous passons à l'API Search, qui attend des paramètres sous la forme « Premier+Deuxième+Troisième+Mots » plutôt que « Premier%20Second%20… », etc. Donc, à la place d'URL-encoding, nous utilisons une méthode NSString appelée stringByReplacingOccurencesOfString. Cela retourne une version modifiée de la variable searchTerm avec tous nos espaces remplacés par des symboles +.

Ensuite, nous protégeons le terme de recherche par une barre oblique inverse, pour le cas où il contient d'autres symboles ne convenant pas pour une URL, en utilisant la fonction stringByAddingPercentEscapeUsingEncoding.

Les deux lignes suivantes définissent un objet NSURL qui peut être utilisé comme URL de requête par l'API réseau de iOS.

Ces deux lignes nous permettent d'obtenir un objet NSURLSession et de définir la tâche que nous voulons que celui-ci accomplisse. C'est ici que la partie complexe commence, car la méthode dataTaskWithURL prend comme dernier argument une fermeture qui est exécutée après l'envoi de la requête, et un résultat est déterminé :

1. let session = NSURLSession.sharedSession()

1. let task = session.dataTaskWithURL(url, completionHandler: {data, response, error -> Void in

La première saisit l'objet NSURLSession par défaut. Celui-ci est utilisé pour tous nos appels à travers le réseau. La seconde ligne crée alors la tâche de connexion qui sera utilisée pour envoyer la requête. dataTaskWithURL a pour dernier paramètre une fermeture qui est lue lors de l'achèvement de la requête. Ici, nous vérifions les erreurs dans la réponse, puis analysons le JSON et appelons la méthode déléguée didReceiveAPIResults.

Enfin, task.resume() lance effectivement la requête.

Parce que cette tâche s'exécute en arrière-plan, nous avons besoin de basculer en premier plan avant de mettre à jour l'interface utilisateur. Nous devons donc utiliser dispatch_async pour revenir dans le thread principal et recharger la vue de la table. Le premier argument indique le thread qui doit être mis à jour, que nous déterminons par dispatch_get_main_queue(). Celle-ci est une méthode interne qui retourne tout simplement le thread principal (le fil d'exécution de l'interface utilisateur).

III - Appeler l'API

Maintenant, nous avons une méthode qui démarre la recherche d'une réponse d'iTunes quand nous l'appelons. Allons insérer le texte suivant à la fin de viewDidLoad…

1. searchItunesFor("JQ Software")

Cela trouvera tous les produits logiciels contenant cette expression et présents sur l'iTunes Store, c'est-à-dire deux ou trois jeux et différentes apps.

IV - Recevoir la réponse

Le code de notre requête est enfin écrit, toutes les données ont été reçues, la méthode déléguée didReceiveAPIResults est appelée et nous sommes prêts à utiliser les données dans notre application. Hourra !

La méthode de fermeture utilise ici la classe NSJSONSerialization pour désérialiser les données brutes obtenues d'iTunes en objets Dictionnaire utilisables.

Nous pouvons maintenant configurer notre objet self.tableData comme donnée résultante et dire à appsTableView de recharger son contenu. Cela entraînera l'exécution des méthodes de délégué propres à l'objet Table View. Définir ceci est la dernière étape de cette partie du tutoriel.

V - Mettre à jour la Table View sur l'interface utilisateur

Vous vous souvenez peut-être de la dernière fois que nous avons mis en œuvre deux fonctions pour notre Table View : une fonction de comptage qui détermine le nombre de lignes et une fonction qui crée la cellule et la modifie pour chaque ligne.

Nous allons maintenant mettre à jour ces fonctions pour utiliser les données obtenues à partir du Web.

Remplacez vos méthodes par ces deux fonctions :

1. func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {

2. return tableData.count

3. }

5. func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {

6. let cell: UITableViewCell = UITableViewCell(style: UITableViewCellStyle.Subtitle, reuseIdentifier: "MaCelluleDeTest")

8. if let rowData: NSDictionary = self.tableData[indexPath.row] as? NSDictionary,

9. // Prenez la clé artworkUrl60 pour obtenir l'URL d'une image pour la miniature de l'application

10. urlString = rowData["artworkUrl60"] as? String,

11. // Créez une instance de NSURL à partir de l'URL sous forme de chaîne que nous recevons de l'API

12. imgURL = NSURL(string: urlString),

13. // Obtenez le prix formaté en chaîne, pour l'afficher dans le sous-titre

14. prixFormate = rowData["formattedPrice"] as? String,

15. // Téléchargez une représentation NSData de l'image à cette URL

16. imgData = NSData(contentsOfURL: imgURL),

17. // Obtenez le titre du morceau

18. nomMorceau = rowData["trackName"] as? String {

19. // Affichez le prix formaté dans le sous-titre

20. cell.detailTextLabel?.text = prixFormate

21. // Mettez à jour la cellule imageWiew pour afficher l'image téléchargée

22. cell.imageView?.image = UIImage(data: imgData)

23. // Mettez à jour le texte de textLabel pour afficher le nom du morceau obtenu de l'API

24. cell.textLabel?.text = nomMorceau

25. }

26. return cell

27. }

Maintenant, numberOfRowsInSection retourne tout simplement le nombre d'objets résultant de la variable tableData, définie dans la version précédente de notre méthode connectionDidFinishLoading.

La méthode cellForRowAtIndexPath n'est pas non plus modifiée de façon spectaculaire dans ce cas. Plutôt que de simplement renvoyer le numéro de ligne, nous l'utilisons pour reprendre trois éléments d'information : le nom du morceau, l'URL de l'illustration et le prix.

Avec ces clés, nous construisons le titre, le sous-titre et une image pour accompagner la cellule.

Si vous connaissez déjà d'autres langages, vous avez peut-être remarqué que la syntaxe y est un peu inhabituelle. Elle ressemble à ceci :

1. if let variableA = optionalThing as? Type,

2. variableB = anotherOptionalThing as? Type {

3. // L'existence de variableA et de variableB est confirmée

4. }

Cela fait partie de la liaison optionnelle. La déclaration if let variableA = optionalThing as? Type {} exécutera le code entre les accolades uniquement si optionalThing peut être converti explicitement en Type. C'est une vérification : pouvons-nous attribuer à une variable appelée variableA un objet optionalThing, de type Type ? Si oui, le code qui suit le test est exécuté. Vous pouvez spécifier plusieurs conditions à tester ; dans le code ci-dessus, nous vérifions si l'on peut attribuer des valeurs tant à variableA qu'à variableB, et si c'est le cas, le bloc de code qui suit le test sera exécuté.

Nous utilisons la liaison optionnelle dans la méthode cellForRowAtIndexPath, afin de nous assurer que artworkurl60, formattedPrice et trackName sont effectivement des clés que nous recevons de l'API comme réponse à notre requête. Si n'importe lequel de ces tests échoue, le code entre les accolades n'est pas exécuté, ce qui évite l'apparition d'une erreur lorsque nous essayons d'attribuer une valeur nil au texte ou à l'image.

Essayez de lancer notre application, et vous verrez que nous avons créé pour la première fois quelque chose qui ressemble vraiment à une application en Swift !

Mais, pourquoi est-elle si lente ?
Si vous faites défiler, vous remarquerez peut-être qu'elle traîne lors de l'affichage des cellules du tableau.
Dans cette tableview, nous ne gérons pas convenablement un certain nombre de choses. Au cours des trois prochaines sections, nous allons voir quels sont les changements appropriés que nous devons faire et leur signification. Si vous voulez, passez directement à la partie 5, où ces problèmes sont résolus.

La prochaine fois, dans la Partie 3, nous allons travailler sur la composante interaction de l'application, qui permet aux utilisateurs de rechercher tout ce qu'ils veulent et de rendre les cellules d'un tableau cliquables !

VI - Code source

Le code source complet de cette section est disponible ici.

VII - Vous avez une question ou un problème ?

Rejoignez-nous sur nos forums.

VIII - Remerciements Developpez

Nous remercions Jameson Quave de nous avoir aimablement autorisés à publier son article, dont le texte original peut être trouvé sur jamesonquave.com. Nous remercions aussi Mishulyna pour sa traduction, LeBzul pour sa relecture technique ainsi que jacques_jean pour sa relecture orthographique.

Aller à la partie 3 maintenant ->

Retrouvez toute la série "Développer des Apps iOS 8 avec Swift"