Tutoriel: Créer une application simple pour iPhone sur iOS 5. Partie 3/3

Ray Wenderlich

Cet article est également disponible en : Chinois simplifié, Anglais, Japonais, Espagnol, Coréen

Sûrement le plus flippant de tous !

Surement le plus flippant de tous !

Mise à jour du 20/02/12 : Adaptation à iOS 5.

Ceci est la troisième et dernière partie d’une série d’articles détaillant la création d’une application iPhone simple, à destination des débutants. L’application permet de noter les insectes les plus flippants !

Dans la première partie, nous avons créé une application qui contient une liste d’insectes dans une table view.

Dans la seconde partie, nous avons vu comment créer la vue détaillée associée à la table view.

Dans cet article, nous allons voir comment créer de nouveaux insectes, comment ajouter une icône et une image le lancement à notre projet, et comment gérer l’exécution des opérations longues.

En avant pour terminer notre application !

Ajouter et supprimer des insectes

Tout fonctionne bien jusque’à présent, mais ce n’est pas vraiment une application qui répond aux attentes des utilisateurs ! La première chose qu’un utilisateur souhaitera faire sera d’ajouter ses propres insectes, et le seul moyen de le faire actuellement est de modifier le code de l’application !

Par chance, nous avons créé notre DetailViewController de sorte à pouvoir modifier un insecte (une partie du travail est donc fait !). Et comme notre contrôleur racine est un UITableViewController, l’infrastructure pour ajouter des données est déjà presque en place ! Nous n’avons qu’à faire quatre changements, je vais les expliquer un par un pour que les choses soient bien comprises :

1) Mettre en place les boutons de navigation

Dans le fichier MasterViewController.m, ajouter les lignes suivantes à la méthode viewDidLoad :

self.navigationItem.leftBarButtonItem = self.editButtonItem;
self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] 
    initWithBarButtonSystemItem:UIBarButtonSystemItemAdd 
    target:self action:@selector(addTapped:)];

Ici, nous venons de configurer des boutons dans la barre de navigation. De façon similaire à « title » qui est une propriété particulière des contrôleurs utilisés par le navigation controller, « navigationItem » en est une autre. Tout ce que l’on assigne aux propriétés leftBarButtonItem et rightBarButtonItem apparaîtra dans la barre de navigation lorsque le ViewController concerné sera affiché par le NavigationController.

Pour le bouton de gauche que l’on assigne à la propriété leftBarButtonItem, nous utilisons un bouton particulier intégré à la classe UITableView : « editButtonItem ». Ce bouton porte le libellé « Edit » et passe la TableView dans un mode d’édition (où l’on peut effacer des rangées, par exemple).

Pour le bouton de droite (rightBarButtonItem), nous créons un bouton que l’utilisateur peut actionner pour créer une nouvelle ligne représentant un insecte. Il se trouve qu’il existe un bouton fourni par le système à cet effet (un bouton contenant le symbole « + »), nous utilisons donc ce bouton, et nous lui assignons la méthode « addTapped: » comme callback (c’est à dire que cette méthode sera appelée lorsque le bouton sera actionné par l’utilisateur).

Remarquez qu’il est également possible de configurer ces boutons dans l’éditeur de Storyboard, mais je souhaitais vous montrer cette façon, moins évidente, de créer les boutons.

2) Implementer tableView:commitEditingStyle:forRowAtIndexPath

Toujours dans le fichier MasterViewController.m, la méthode tableView:commitEditingStyle:forRowAtIndexPath qui se trouve en commentaires doit être activée. Remplacez son contenu par les lignes de code suivantes :

if (editingStyle == UITableViewCellEditingStyleDelete) {        
    [_bugs removeObjectAtIndex:indexPath.row];
    [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
}

Cette méthode est appelée quant l’utilisateur choisit de modifier une rangée de la TableView. On vérifie si l’utilisateur essaie de supprimer une rangée, et si c’est le cas, on exécute cette action. Notez que nous devons la supprimer à la fois dans notre modèle de données (_bugs) mais aussi directement dans la TableView avec le message deleteRowsAtIndexPaths.

3) Gérer la création d’un insecte

Ensuite, ajoutez cette méthode au fichier MasterViewController.m:

- (void)addTapped:(id)sender {
    ScaryBugDoc *newDoc = [[ScaryBugDoc alloc] initWithTitle:@"New Bug" rating:0 thumbImage:nil fullImage:nil];
    [_bugs addObject:newDoc];
 
    NSIndexPath *indexPath = [NSIndexPath indexPathForRow:_bugs.count-1 inSection:0];
    NSArray *indexPaths = [NSArray arrayWithObject:indexPath];    
    [self.tableView insertRowsAtIndexPaths:indexPaths withRowAnimation:YES];
 
    [self.tableView selectRowAtIndexPath:indexPath animated:YES scrollPosition:UITableViewScrollPositionMiddle];
    [self performSegueWithIdentifier:@"MySegue" sender:self];    
}

À la première étape, nous avions configuré le bouton « + » de telle sorte que cette méthode soit appelée lorsqu’il est actionné.

Ici, nous créons une nouvelle instance de classe ScaryBugDoc avec des valeurs par défaut. Et nous mettons à jour la TableView pour lui signaler l’apparition d’une nouvelle rangée.

Ensuite, nous ajoutons du code qui agit comme si l’utilisateur de l’application avait sélectionné la nouvelle rangée, de sorte à présenter directement l’écran d’édition. Pour cela, on sélectionne la rangée de la table, et on actionne la transition (en anglais segue) qui a été mise en place dans l’éditeur de Storyboard.

Remarquez que nous n’avons pas encore nommé le segue « MySegue » dans le fichier Storyboard, faisons-le maintenant.

4) Nommer le segue (la transition)

Ouvrir MainStoryboard.storyboard et cliquer sur la flèche portant une icône entre la vue d‘accueil et la vue détaillée — c’est notre Segue.

Ensuite, dans le quatrième onglet du panneau de droite (Attributes Inspector), assignez la valeur « MySegue » à l’attribut Identifier. Ainsi, nous pouvons le lancer quand nous le souhaitons à partir du code.

Donner un nom à un segue dans Xcode

Et voilà ! Si vous compilez et lancez l’application, vous devriez maintenant pouvoir ajouter vos insectes (bugs !), comme celui-ci par exemple :

Un bug Objective-C

Ajouter une icône et une image de lancement

Bien, notre application est amusante, il est temps de la distribuer pour devenir riches !

Mais dans son état actuel, ce serait un peu embarrassant, nous n’avons même pas d’icône !

Heureusement, c’est un défaut facile à corriger. Plus tôt, nous avons déjà ajouté à notre projet l’icône nommée « logo1.png », parmi les fichiers de l’archive ExtraStuffForScaryBugs2.zip. Il nous suffit d’assigner à ce fichier le rôle d’icône de l’application.

Pour cela, sélectionnez le projet ScaryBugs dans le panneau de gauche (Project Navigator), puis cliquez sur le target ScaryBugs. Dans l’onglet « Summary », faites défiler vers le bas jusqu’à la section « icônes ». Faites un Ctrl-clic sur la première icône et choisissez « Select File » :

Changement d’icône du projet dans Xcode

Choisissez le fichier logo1.png dans le répertoire du projet, acceptez les messages d’avertissement, et vous devriez voir l’icône apparaître.

Remarquez que cette méthode est un raccourci pour éviter de modifier soi-même le fichier ScaryBugs-Info.plist dans lequel différents réglages de l’application sont stockés. Vous pouvez le vérifier en ouvrant le fichier ScaryBugs-Info.plist, et vous devriez voir ce qui suit :

Réglage de l’icone dans le fichier info.plist

Il est donc possible de choisir l’icône de l’application uniquement par ce fichier, mais l’utilisation de l’interface graphique est plus simple.

Supprimez et ré-installez l’application dans le simulateur ou sur votre iPhone, et l’application possède maintenant une icône !

Scary Bugs avec sa nouvelle icône

Il y a autre chose que nous devons réparer. Vous avez peut-être remarqué que lorsque nous lançons ScaryBugs, c’est d’abord un écran noir qui apparaît. C’est un comportement embarrassant, cela donne l’impression que notre application n’est pas très réactive.

Selon la documentation d’Apple, la meilleure chose à faire est d’afficher à la place de cet écran noir une image qui ressemble notre application mais sans les données qu’elle contient. C’est plutôt facile à faire, ouvrez le fichier MasterController.m et faites le changement suivant :

// Remplacez la dernière ligne de la méthode tableView:numberOfRowsInSection's par:
return 0; // return _bugs.count;

Lancez l’application sur votre iPhone et vous verrez une TableView vide. Dans XCode, cliquez sur le bouton Organizer dans la barre du haut (à droite), puis cliquez sur votre appareil connecté. Allez dans l’onglet « Screenshots » et cliquez sur « New Screenshot » (en bas) pour obtenir une capture de l’écran :

Faire une capture d’écran dans l’Organizer

Ensuite, cliquez sur « Save as Launch Image », conservez le nom « Default » et validez par le bouton Next. L’image est alors ajoutée à votre projet et configurée comme image de lancement, pratique !

Dans le simulateur, vous pouvez également faire une capture d’écran (dans le menu « Fichier »). À vous ensuite de la configurer comme image de lancement.

Vous pouvez vérifier que l’image est bien configurée en retournant sur l’onglet « Summary » du projet :

Image de lancement dans XCode

Enfin, rétablissez la méthode tableView:numberOfRowsInSection à son état initial, nous l’avions uniquement modifiée pour cacher les données temporairement. Désormais, au lancement de l’application, la table vide s’affiche puis se remplit avec les données, cela lui donne un aspect plus rapide !

Bonus : Gérer les opérations longues

Si vous lancez l’application dans le simulateur, tout semble bien fonctionner, mais si vous l’utilisez sur votre iPhone et touchez une image d’insecte pour la modifier, il y a un LONG délai pendant que l’objet UIImagePicker s’initialise : l’application se bloque pendant ce temps. Après avoir choisi une image, il y a un autre délai plutôt long pendant le changement de dimensions de l’image (surtout si celle-ci est grande). C’est quelque chose qu’il nous faut modifier.

La règle à mémoriser est qu’il ne faut jamais effectuer d’opérations longues dans le thread principal (le thread est parfois appelé « fil d’exécution » mais reste principalement nommé en anglais par les informaticiens francophones). Nous n’avons pas respecté cette règle et le résultat est que notre application semble totalement bloquée à certains moments.

Ce que nous devons faire est de placer les opérations longues dans un thread séparé qui s’exécutera en tâche de fond. Idéalement, ces opérations pourraient s’exécuter pendant que l’utilisateur continue à faire d’autres choses dans l’application, mais si la tâche doit se finir avant de redonner la main à l’utilisateur (par exemple pour qu’il puisse choisir une image), nous devrions au moins afficher un indicateur de chargement ou un élément permettant de lui faire comprendre que l’application est en train de travailler, qu’elle ne s’est pas bloquée.

Ce que nous allons faire ici, pendant que notre tâche de fond se déroule, c’est afficher une vue « Loading » au premier plan, indiquant à l’utilisateur qu’un chargement est en cours.

Le besoin d’afficher une vue d’attente pour un chargement est très commun pour les développeurs. Certains ont créé des indicateurs d’activité que nous pouvons utiliser plutôt que d’en créer de nouveaux. J’en ai essayé plusieurs et mon favori est actuellement SVProgressHUD par Sam Vermette, utilisons-le ! Vous pouvez le télécharger sur la page Github de SVProgressHUD.

Une fois téléchargé, ajoutez les fichiers SVProgressHUD.h et SVProgressHUD.m au projet, dans le groupe « Views ». Il vous faut également procéder à une étape de configuration :

Ajouter la bibliothèque requise. Cliquez sur le projet dans le Project Navigator et sélectionnez le target ScaryBugs. Dans l’onglet Build Phases, ouvrez la section « Link Binary With Libraries » et ajoutez QuartzCore.framework à l’aide du bouton « + ».

Ajout de la bibliothèque QuartzCore.framework

Notez que dans cet écran, il est possible de choisir des options avancées qui peuvent vous servir lorsque vous utilisez des classes créées par quelqu’un d’autre : Si les classes ne sont pas compatible avec la technologie ARC d’Apple (qui est relativement récente), vous pouvez ouvrir la section « Compile Sources », double-cliquer sur la classe pour laquelle vous souhaitez désactiver ARC, et entrer -fno-objc-arc dans la boîte de dialogue. Ceci n’est pas nécessaire pour SVProgressHUD mais cette information pourra vous être utile.

À ce stade, le projet devrait se compiler sans erreurs.

Procédez maintenant aux changements suivants dans le fichier DetailViewController.m :

// En haut
#import "SVProgressHUD.h"
 
// Remplacez addPictureTapped par ce qui suit:
- (IBAction)addPictureTapped:(id)sender {
    if (self.picker == nil) {   
 
        // 1) Afficher l’état
        [SVProgressHUD showWithStatus:@"Loading picker..."];
 
        // 2) Obtenir un fil d’exécution séparé
        dispatch_queue_t concurrentQueue =
        dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
 
        // 3) Charger UIImagePicker en tâche de fond
        dispatch_async(concurrentQueue, ^{
 
            self.picker = [[UIImagePickerController alloc] init];
            self.picker.delegate = self;
            self.picker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
            self.picker.allowsEditing = NO;    
 
            // 4) Afficher l’image picker dans le thread principal
            dispatch_async(dispatch_get_main_queue(), ^{
                [self.navigationController presentModalViewController:_picker animated:YES];    
                [SVProgressHUD dismiss];
            });
 
        });        
 
    }  else {        
        [self.navigationController presentModalViewController:_picker animated:YES];    
    }
}

Il y a de nombreuses choses à expliquer ici, allons-y section par section.

  1. Ici, nous utilisons la classe SVProgressHUD que nous venons d’ajouter pour afficher la vue « Loading » avec une animation d’attente. Ainsi, l’utilisateur sait qu’il se passe quelque chose, que l’application n’est pas bloquée.
  2. Nous souhaitons charger l’image picker en tâche de fond. Nous pouvons le faire à l’aide de la technologie d’iOS nommée Grand Central Dispatch. Nous n’entrerons pas dans les détails ici (mais si vous êtes curieux, consultez ce tutoriel). Pour l’instant, tout ce que vous devez savoir est que cette ligne nous fournit une file (queue) dans laquelle nous placerons des blocks de code à exécuter.
  3. Cette ligne exécute le block de code pour charger l’image picker en tâche de fond. Si vous n’êtes pas à l’aise avec la syntaxe des blocks, consultez ce tutoriel.
  4. Finalement, nous affichons l’image picker dans le thread principal. Notez qu’il est indispensable de mettre à jour l’interface à partir du thread principal — vous ne pouvez pas le faire dans le block qui s’exécute en tâche de fond.

De même, nous pouvons effectuer le redimensionnement d’image en tâche de fond. Remplacez la méthode imagePickerController:didFinishPickingMediaWithInfo par celle-ci :

- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {    
 
    [self dismissModalViewControllerAnimated:YES];
 
    UIImage *fullImage = (UIImage *) [info objectForKey:UIImagePickerControllerOriginalImage]; 
 
    // 1) Afficher l’état
    [SVProgressHUD showWithStatus:@"Resizing image..."];
 
    // 2) Obtenir un fil d’exécution séparé
    dispatch_queue_t concurrentQueue =
    dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
 
    // 3) Redimensionner l’image en tâche de fond
    dispatch_async(concurrentQueue, ^{
 
        UIImage *thumbImage = [fullImage imageByScalingAndCroppingForSize:CGSizeMake(44, 44)];
 
        // 4) Afficher l’image dans le thread principal
        dispatch_async(dispatch_get_main_queue(), ^{
            self.detailItem.fullImage = fullImage;
            self.detailItem.thumbImage = thumbImage;
            self.imageView.image = fullImage;
            [SVProgressHUD dismiss];
        });
 
    });
 
}

Et voilà ! Lancez-le sur votre appareil et vous verrez une nouvelle animation pendant les exécutions de tâches longues. Cela améliore beaucoup l’expérience utilisateur.

Utilisation de SVProgressHUD

Et maintenant ?

Voici le fichier du projet avec tout le code que nous avons fait dans cette série de trois tutoriels.

Félicitations, vous avez fini la création d’une application iOS selon le modèle Master / Detail. Vous avez plongé dans un cours intensif couvrant tous les aspects de création d’une application, vous pouvez maintenant approfondir les domaines qui vous intéressent.

Voici ce que je vous recommande de lire maintenant :

  • The iOS Apprentice : Matthijs Hollemans, membre de l’équipe de rédaction des tutoriels iOS, a écrit (en anglais) une série détaillée couvrant tout ce qu’un développeur iOS débutant doit savoir pour bien démarrer avec iOS. Vous pouvez obtenir la première partie gratuitement en vous abonnant à la newsletter iOS mensuelle, ou en achetant la série complète dans le magasin raywenderlich.com.
  • Beginning Storyboards in iOS 5 Tutorial : Pour mettre en forme votre interface utilisateur dans iOS 5, vous allez avoir besoin d’utiliser l’éditeur de Storyboard, apprenez à vous en servir !
  • Beginning ARC in iOS 5 Tutorial : Il est également important de comprendre comment fonctionne la gestion de la mémoire dans iOS 5 (et à quel point c’est facile avec ARC !)
  • How To Use Blocks in iOS 5 Tutorial : Si vous démarrez avec l’utilisation des blocks, vous devriez lire ce tutoriel. Il donne également quelques conseils d’utilisation des Storyboards.
  • Multithreading and Grand Central Dispatch on iOS : Il est aussi utile d’apprendre comment gérer les tâches de fond pour garder une application réactive. Ce tutoriel y a juste touché du doigt, lisez celui-ci pour de plus amples détails.
  • How To Submit Your App to the App Store : Et bien sûr, quand vous avez fini votre application, vous souhaitez la diffuser sur l’App Store ! Voici un guide pas-à-pas pour y parvenir.
  • Et bien plus encore ! Nous avons des tonnes de tutoriels iOS sur ce site. Suivez ce lien pour voir la liste entière !

Je vous souhaite bonne chance dans vos aventures avec iOS, et j’espère que vous avez apprécié construire l’application ScaryBugs ! Si vous avez des questions ou des commentaires, merci de vous joindre à la discussion plus bas !

Ray Wenderlich

Ray is an indie software developer currently focusing on iPhone and iPad development, and the administrator of this site. He’s the founder of a small iPhone development studio called Razeware, and is passionate both about making apps and teaching others the techniques to make them.

When Ray’s not programming, he’s probably playing video games, role playing games, or board games.

Commentaires

1 Comment

  • Bonjour,

    J'ai beaucoup aim votre tuto que j'ai ralis sans grosse difficult car trs bien dtaill.

    je voulais savoir comment je pourrais faire pour afficher du texte dans un label en dessous de la grande image qu'on peux voir dans le DetailVc?
    comme a on pourrai rajouter des commentaire sur la dure de vie de l'insecte par exemple, sa rgion de prdilection etc.. que l'utilisateur ne peut pas modifier, juste lire.

    j'ai essay de le faire mais je n'y arrive pas. J'ai rajouter un label dans le Detail Vc, dclarer dans le ScaryBugData et ScrayBugDoc et essay de completer la methode dans l'Appdelegate mais l coince et je ne trouve pas o. pouvez vous m'clairer de vos connaissance svp. Je suis novice et autodidacte donc soyez indulgent et dtaill dans vos explication. Je vous remercie d'avance
    misterarmani

Other Items of Interest

Newsletter mensuelle de Ray

Inscrivez-vous pour recevoir une newsletter mensuelle avec mes liens de développement favoris et recevez un très long tutoriel gratuit comme bonus!

Annoncez avec nous!

Nos livres

Notre Equipe

Tutorial Team

  • Jean-Pierre Distler
  • Barbara Reichart
  • Kyle Richter

... 50 en tout!

Update Team

  • Zouhair Mahieddine

... 15 en tout!

Equipe de rédaction

... 23 en tout!

Code Team

  • Orta Therox

... 3 en tout!

Équipe de traduction

  • Miguel Angel
  • David Xie
  • David Hidalgo

... 33 en tout!

Spécialistes en la matière

  • Richard Casey

... 4 en tout!