You are on page 1of 451

Dveloppez vos applications pour

iPhone, iPod Touch, iPad

Copyright

2010 Micro Application 20-22, rue des Petits-Htels 75010 Paris 1re dition - Mai 2010

Auteur

Jean-Pierre IMBERT Toute reprsentation ou reproduction, intgrale ou partielle, faite sans le consentement de MICRO APPLICATION est illicite (article L122-4 du code de la proprit intellectuelle). Cette reprsentation ou reproduction illicite, par quelque procd que ce soit, constituerait une contrefaon sanctionne par les articles L335-2 et suivants du code de la proprit intellectuelle. Le code de la proprit intellectuelle nautorise aux termes de larticle L122-5 que les reproductions strictement destines lusage priv et non destines lutilisation collective dune part, et dautre part, que les analyses et courtes citations dans un but dexemple et dillustration.

Avertissement aux utilisateurs

Les informations contenues dans cet ouvrage sont donnes titre indicatif et nont aucun caractre exhaustif voire certain. A titre dexemple non limitatif, cet ouvrage peut vous proposer une ou plusieurs adresses de sites Web qui ne seront plus dactualit ou dont le contenu aura chang au moment o vous en prendrez connaissance. Aussi, ces informations ne sauraient engager la responsabilit de lEditeur. La socit MICRO APPLICATION ne pourra tre tenue responsable de toute omission, erreur ou lacune qui aurait pu se glisser dans ce produit ainsi que des consquences, quelles quelles soient, qui rsulteraient des informations et indications fournies ainsi que de leur utilisation. Tous les produits cits dans cet ouvrage sont protgs, et les marques dposes par leurs titulaires de droits respectifs. Cet ouvrage nest ni dit, ni produit par le(s) propritaire(s) de(s) programme(s) sur le(s) quel(s) il porte et les marques ne sont utilises qu seule n de dsignation des produits en tant que noms de ces derniers. ISBN : 978-2-300-028021 ISSN : 1950-0289 MICRO APPLICATION 20-22, rue des Petits-Htels 75010 PARIS Tl. : 01 53 34 20 20 Fax : 01 53 34 20 00 http://www.microapp.com Support technique : galement disponible sur www.microapp.com

Retrouvez des informations sur cet ouvrage ! Rendez-vous sur le site Internet de Micro Application www.microapp.com. Dans le module de recherche, sur la page daccueil du site, entrez la rfrence 4 chiffres indique sur le prsent livre. Vous accdez directement sa che produit.

2802

Avant-propos
Destine aussi bien aux dbutants quaux utilisateurs initis, la collection Guide Complet repose sur une mthode essentiellement pratique. Les explications, donnes dans un langage clair et prcis, sappuient sur de courts exemples. En n de chaque chapitre, dcouvrez, en fonction du sujet, des exercices, une check-list ou une srie de FAQ pour rpondre vos questions. Vous trouverez dans cette collection les principaux thmes de lunivers informatique : matriel, bureautique, programmation, nouvelles technologies...

Conventions typographiques
An de faciliter la comprhension des techniques dcrites, nous avons adopt les conventions typographiques suivantes :
j j

gras : menu, commande, bote de dialogue, bouton, onglet. italique : zone de texte, liste droulante, case cocher, bouton

j j

radio. Police bton : Instruction, listing, adresse internet, texte saisir. : indique un retour la ligne volontaire d aux contraintes de la mise en page.

Il sagit dinformations supplmentaires relatives au sujet trait.

Met laccent sur un point important, souvent dordre technique quil ne faut ngliger aucun prix.

Propose conseils et trucs pratiques.

Donne en quelques lignes la dnition dun terme technique ou dune abrviation.

Chapitre 1
1.1.

Premiers pas

17

1.2. 1.3. 1.4.

1.5. 1.6. 1.7.

Crer un projet avec XCode ............................................ 19 Lancer XCode ............................................................ 19 Crer un projet ........................................................... 20 Grer le projet ............................................................ 23 Composer linterface utilisateur ....................................... 25 Tester lapplication ...................................................... 28 Finaliser lapplication ................................................... 30 Ajouter un chier au projet ............................................. 30 Dclarer le logo de lapplication ....................................... 32 Agrmenter lapplication ............................................... 34 Mettre notre image dans la vue ....................................... 35 Challenge ................................................................. 36 Check-list .................................................................. 38

Chapitre 2
2.1.

Interactions simples

39

2.2.

2.3.

2.4.

2.5.

Programmation oriente objet ........................................ 41 Objets ...................................................................... 42 Classes .................................................................... 43 Messages ................................................................. 44 Mcanisme Cible-Action ............................................... 44 Crer les outlets .......................................................... 45 Prparer linterface utilisateur ......................................... 47 Connecter les outlets .................................................... 50 Dclarer les actions ...................................................... 51 Dnir les actions ........................................................ 52 Connecter les cibles ..................................................... 57 Construire et tester lapplication Convertisseur1 ................... 59 Hirarchie des classes de Convertisseur1 ........................... 60 Hritage ................................................................... 60 Hirarchie des vues ..................................................... 62 Manipulation des objets en Objective-C ............................. 63 Dclaration ............................................................... 63 Dnition .................................................................. 68 Messages ................................................................. 68 Proprits ................................................................. 69 Cration ................................................................... 70 Libration ................................................................. 72 Check-list .................................................................. 73

Chapitre 3
3.1.

Gestion de la mmoire

75

3.2.

Diagnostiquer les fuites mmoire avec Leaks ....................... 77 Zombi ...................................................................... 77 Dtecter les fuites mmoire ............................................ 78 Diagnostiquer les fuites mmoire ..................................... 82 viter les fuites mmoire ............................................... 84 Compteur de rfrences ................................................ 84 Gestion des proprits .................................................. 84

Sommaire

3.3.

3.4.

Responsabilits des objets ............................................. 88 Amliorer Convertisseur1 .............................................. 90 Instances manipules ................................................... 90 Mise en conformit avec la rgle ...................................... 91 Rfrences obsoltes ................................................... 94 Check-list .................................................................. 98

Chapitre 4
4.1.

Motifs fondamentaux

99

4.2.

4.3. 4.4.

4.5.

Mcanisme de dlgation ............................................ 101 Dlgu .................................................................. 101 Dlguer le champ dollar ............................................. 102 Dlgu pour un champ de texte .................................... 105 Dclarer un protocole ................................................. 107 Lancement de lapplication ........................................... 108 Structurer une application ............................................ 114 Amliorer Convertisseur1 ............................................ 115 Retrouver la virgule .................................................... 115 Localiser lapplication ................................................. 120 Utiliser le motif KVC ................................................... 125 Autres amliorations .................................................. 129 Motif MVC ............................................................... 133 Challenges .............................................................. 134 Amliorer encore Convertisseur1 ................................... 134 Explorer les contrles simples ....................................... 135 Check-list ................................................................ 140

Chapitre 5
5.1.

Applications multivues

143

5.2.

5.3.

5.4.

5.5.

5.6.

Application de type utilitaire ......................................... 145 Comprendre le fonctionnement dun utilitaire .................... 145 Activer une vue modale ............................................... 153 Application Convertisseur2 ........................................... 154 Composer la vue principale .......................................... 154 Paramtrer le taux de conversion ................................... 155 Factoriser le dlgu de champ de texte ........................... 156 Finaliser les contrleurs de vue ...................................... 159 Communiquer entre les deux contrleurs ......................... 166 Messages dalerte ...................................................... 168 Afficher une alerte ...................................................... 169 Feuilles daction ........................................................ 172 Dlgu de feuille daction ........................................... 174 Dlgu dalerte ........................................................ 174 Barre donglets ......................................................... 175 Crer une barre donglet .............................................. 175 Utiliser un contrleur de barre donglets ........................... 177 Modier la navigation par onglets .................................. 180 Barres de navigation ................................................... 181 Crer une barre de navigation ....................................... 182 Utiliser une barre de navigation ..................................... 182 Checklist ................................................................. 183

Sommaire

SOMMAIRE

Chapitre 6
6.1.

Contrles complexes

185

6.2.

6.3.

6.4.

Utiliser un slectionneur .............................................. 187 Slectionneur de date ................................................. 187 Slectionneur standard ............................................... 196 Source de donnes .................................................... 200 Adapter le slectionneur au contexte ............................... 202 Utiliser les conteneurs Cocoa ........................................ 205 Tableaux NSArray ...................................................... 205 Dictionnaires NSDictionary ........................................... 207 Conteneurs mutables .................................................. 208 Utiliser les Vues en table .............................................. 208 Prsentation gnrale ................................................. 208 Crer une vue en table ................................................. 211 Afficher la table ......................................................... 212 Ragir une slection ................................................. 218 Ajouter un lment .................................................... 221 Pour aller plus loin ..................................................... 228 Checklist ................................................................. 228

Chapitre 7
7.1.

Persistance des donnes

231

7.2.

7.3.

Utiliser le framework Core Data ...................................... 233 Dcrire le modle de donnes ....................................... 234 Comprendre le fonctionnement de Core Data ..................... 239 Formuler des requtes ................................................ 247 Ajouter un objet ........................................................ 251 Supprimer un objet .................................................... 254 Utiliser les listes de proprits ....................................... 258 Format des listes de proprits ...................................... 258 Utilisation des listes de proprits .................................. 259 Mise en pratique ........................................................ 260 Checklist ................................................................. 264

Chapitre 8
8.1.

Dessins et animations

267

8.2.

8.3.

8.4.

Animer les images ..................................................... 269 Images animes ........................................................ 269 Sonoriser une application ............................................ 273 Dplacer une image .................................................... 274 Dessiner avec Quartz2D ............................................... 282 Principe de fonctionnement .......................................... 282 Mise en pratique ........................................................ 284 Primitives graphiques ................................................. 289 Dbuter la 3D avec OpenGL ES ...................................... 290 Prsentation dOpenGLES ............................................ 291 Intgration dans Cocoa Touch ....................................... 291 Exemple dapplication ................................................. 295 Checklist ................................................................. 299

Sommaire

Chapitre 9
9.1.

Tapes, touches et gestes

301

9.2.

9.3.

9.4.

Comprendre les vnements ......................................... 303 Classe UIResponder ................................................... 303 vnements lmentaires ............................................ 304 cran Multi-Touch ...................................................... 306 Traiter les vnements ................................................ 307 Recevoir les vnements ............................................. 307 Notication dvnements ........................................... 310 Tapes multiples ......................................................... 312 Mettre en uvre les gestes ........................................... 313 Chiquenaude ............................................................ 313 Pincement ............................................................... 317 Checklist ................................................................. 320

Chapitre 10 Appareil photo


10.1.

321

10.2.

10.3.

10.4. 10.5.

10.6.

Slectionner une photo ............................................... 323 Codage de linterface .................................................. 323 Codage du contrleur de vue ......................................... 325 Classe UIImagePickerController ..................................... 328 Protocole UIImagePickerControllerDelegate ...................... 330 Prendre des photos .................................................... 331 Adapter linterface utilisateur ........................................ 331 Adapter le slectionneur de photos ................................. 331 Enregistrer ses photos ................................................ 332 Grer une image sous Core Data .................................... 332 Enregistrer dans lalbum .............................................. 334 diter les photos ........................................................ 336 Envoyer ses photos .................................................... 336 Classe MFMailComposeViewController ............................ 337 Protocole MFMailComposeViewControllerDelegate ............. 338 Challenge ................................................................ 339 Checklist ................................................................. 339

Chapitre 11 Go-localisation
11.1.

341

11.2.

11.3.

Dterminer sa position ................................................ 343 Technologies de go-localisation .................................... 343 Classe CLLocationManager .......................................... 343 Protocole CLLocationManagerDelegate ............................ 347 Classe CLLocation ...................................................... 348 Challenge ................................................................ 349 Dterminer lorientation gographique ............................ 349 Mise en uvre du compas magntique ............................ 350 Calibration magntique ............................................... 351 Classe CLHeading ...................................................... 351 Framework MapKit ..................................................... 352 Afficher une carte ....................................................... 352 Connatre la zone affiche ............................................. 354 Contrler la zone affiche ............................................. 357 Apprhender la vue satellite .......................................... 358

Sommaire

11.4.

Annoter la carte ......................................................... 359 Checklist ................................................................. 360

Chapitre 12 Acclromtres
12.1.

363

12.2. 12.3.

12.4.

Utiliser les acclromtres ........................................... 365 Visualiser lacclration ............................................... 366 Visualiser la verticale .................................................. 369 Filtrer les donnes ..................................................... 372 Dterminer les mouvements de lappareil ......................... 375 Connatre lorientationde lappareil ................................. 375 Retour sur la classe UIDevice ........................................ 377 Sabonner aux changements dorientation ........................ 377 Orienter automatiquement les vues ................................ 378 Checklist ................................................................. 381

Chapitre 13 Spcicits de liPad


13.1.

383

13.2.

13.3.

13.4.

Un SDK, deux cibles ................................................... 385 Choisir sa cible de dploiement ...................................... 385 Crer une application universelle ................................... 387 Nouveauts de linterface visuelle .................................. 387 Recommandations gnrales ........................................ 387 Vues modales ........................................................... 389 Vues contextuelles ..................................................... 390 Vues scindes ........................................................... 392 Reconnaissance des gestes .......................................... 396 Gestes de base .......................................................... 396 Utiliser un analyseur de geste ........................................ 399 Synchroniser les analyseurs ......................................... 404 Checklist ................................................................. 405

Chapitre 14 Annexe
14.1. 14.2.

407

14.3.

pilogue ................................................................. 409 Politique dApple ....................................................... 409 Les diffrents statuts de dveloppeur ............................... 409 Diffusion des applications ............................................ 410 Signature du code ...................................................... 411 Certicats ................................................................ 412 Processus de diffusion ................................................ 412 Senregistrer comme dveloppeur .................................. 413 Sinscrire au programme des dveloppeurs ....................... 413 Certier un dveloppeur .............................................. 417 Tester son application sur un appareil .............................. 420 Diffusion limite de son application ................................. 426 Diffuser son application sur lAppStore ............................ 434

Chapitre 15 Index

439

Sommaire

INTRODUCTION
Pour qui est ce livre ?
Ce livre est destin tous ceux qui souhaitent dvelopper leur propre application pour iPhone, iPod Touch ou pour iPad. Il vous accompagnera dans ltude de la programmation pour ces quipements, dans la dcouverte des outils de dveloppement dApple et du langage Objective-C ; et jusqu la distribution de votre application sur lAppStore.

iPhone, iPod Touch, iPad


Nous employons le terme iPhone pour voquer indistinctement liPhone liPod Touch ou liPad. Lorsquune caractristique est disponible uniquement sur lun ou lautre de ces appareils, nous le prcisons en indiquant par exemple : "cette caractristique nest pas disponible sur iPod Touch".

Vous explorerez les techniques permettant dutiliser les caractristiques les plus innovantes de liPhone (acclrateur, go-localisation, capacits graphiques, gestes, etc.) et serez certainement sduit par la

INTRODUCTION

dsarmante facilit avec laquelle vous mettrez en uvre ces techniques en utilisant les frameworks et le SDK dApple. Cet ouvrage est destin ceux qui ont dj une connaissance de la programmation dapplications logicielles. Si ce nest pas le cas, nous vous recommandons la lecture de Dbutez en Programmation (ditions Micro Application).

Dvelopper pour iPhone ou pour iPad ?


Les applications dveloppes pour iPhone et iPod Touch peuvent tre excutes sur iPad. Lutilisateur a alors la possibilit de visualiser linterface dans sa taille originale ou dans une taille double. linverse, une application dveloppe pour iPad ne peut gnralement pas tre excute sur iPhone ou iPod Touch, ne serait ce que pour la taille de lcran. Pour ces trois appareils, il faut utiliser le SDK iPhone OS. Il est donc a priori plus intressant de dvelopper pour iPhone plutt que seulement pour iPad. La plupart des chapitres de cet ouvrage traitent donc de liPhone et de liPod Touch. Le dernier chapitre traite des spcicits de liPad et de la ralisation dapplications qui sadaptent lappareil sur lequel elles sexcutent.

De quoi avez-vous besoin ? Comment lobtenir ?


Le matriel
SDK Apple
Le SDK Apple ne fonctionne pas sur un PC sous Windows ou Linux.

Lenvironnement de dveloppement utilis dans cet ouvrage est le SDK 3.2 qui permet de dvelopper des applications pour iPhone, iPod Touch et iPad. Il ne peut sexcuter que sur un Macintosh processeur Intel dot du systme dexploitation Snow Leopard (Mac OS X 10.6) ou ultrieur.

10

Introduction

Intel ou PowerPC
Durant de longues annes, une particularit des Macintosh dApple tait de fonctionner sur un processeur de la famille PowerPC, dvelopp en collaboration avec IBM et Motorola, et pas sur un processeur de la famille Pentium ou quivalent comme les PC. partir du dbut des annes 2000, lcart de performances entre ces deux types de processeur sest progressivement accru en faveur dIntel, si bien que Steve Jobs a annonc en juin 2005 le changement de processeur. Tous les Macintosh partir de 2006 sont processeur Intel et conviennent pour le dveloppement sur iPhone.

Si ce nest dj fait, il vous faudra donc imprativement vous procurer un Mac si vous voulez dvelopper des applications pour iPhone.

Le Refurb Store
Apple commercialise des produits reconditionns sur son site marchand http://store.apple.com/fr. Il est possible dy faire de bonnes affaires. Si vous tes tudiant, pensez aussi aux offres spciales "ducation" dApple.

Figure 1 : Les produits reconditionns sur lApple Store


Plusieurs revendeurs commercialisent galement des machines doccasion, soyez sr de choisir un Mac processeur Intel.

Le logiciel
Lenvironnement de dveloppement est disponible gratuitement sur le site des dveloppeurs dApple http://developer.apple.com. Dans la suite

De quoi avez-vous besoin ? Comment lobtenir ?

11

de cet ouvrage, nous emploierons le terme de SDK (Software Development Kit) pour dsigner lenvironnement de dveloppement.

Inscription obligatoire
Linscription sur le site des dveloppeurs dApple est obligatoire pour tlcharger le SDK. Cette inscription est gratuite, elle vous permettra galement daccder aux ressources techniques du site des dveloppeurs (vidos dapprentissage, documentation technique, exemples de code source, forum des dveloppeurs).

lheure o nous rdigeons ces lignes, le SDK est disponible en version 3.1.2 qui permet de dvelopper des applications pour les versions 2 et 3 diPhone OS. Il est fourni au format .dmg (format dimage disque standard sur Mac OS X) et sa taille est environ de 2,7 Go ; il faut gnralement plusieurs heures pour le tlcharger. Vous obtiendrez un SDK complet et dexcellente qualit :

j j j

outils de dveloppement ; frameworks iPhone/iPod Touch/iPad et Mac OS X ; simulateur diPhone et diPad pour tester vos applications sur votre Macintosh ; outils et instruments divers (mesure de performance, recherche de bogues, ateliers de composition graphique, etc.).

1 Double-cliquez sur le chier que vous venez de tlcharger ; une fentre du Finder souvre qui vous permet de visualiser le contenu de limage disque. 2 Double-cliquez sur le chier iPhone SDK ; le programme dinstallation sexcute et suit le processus standard sur Mac OS X : approbation de la licence dutilisation des outils de dveloppement puis du kit iPhone, personnalisation de linstallation (laisser les paramtres par dfaut) et installation.

Installation et droits dadministration


Linstallation du SDK ncessite les droits dadministration de lordinateur.

12

Introduction

Figure 2 : Contenu de limage disque du SDK iPhone

Un appareil de test
Vous pourrez tester plusieurs applications de ce livre en utilisant le simulateur fourni avec le SDK mais votre satisfaction sera dcuple lorsque vous excuterez votre application sur votre appareil. Il nest gnralement pas ncessaire de disposer dun appareil spcique pour effectuer vos tests ; liPhone, liPod Touch ou liPad que vous utilisez quotidiennement fera laffaire. Si vous souhaitez amliorer les tests avant de diffuser votre application, vous devrez disposer de plusieurs appareils, par exemple un iPhone 3G, un iPhone 3GS, un iPod Touch et un iPad. Certaines personnes de votre entourage disposent srement de ces appareils et seront sans doute ers de vous aider tester vos applications. An de viser une plus large diffusion, il faudra tester vos applications non seulement sur plusieurs appareils mais aussi sous plusieurs versions dOS. Il vaudra mieux ce moment-l que vous disposiez dappareils dont lusage sera rserv aux tests ; vous risquez davoir moins damis si les changements dOS ont provoqu des pertes de donnes sur les appareils quils vous ont cons.

Linscription au programme des dveloppeurs iPhone


Cette inscription payante, moins de 100 5 par an, est indispensable pour tester son application sur un appareil rel. Elle vous permettra de :
j

tester ou diffuser en mode Priv vos applications sur des appareils rels (jusqu 100) ;

De quoi avez-vous besoin ? Comment lobtenir ?

13

j j j

diffuser vos applications sur lAppStore (et gagner de largent) ; disposer des versions Bta de liPhone OS ; accder certaines informations spciques.
Linscription se fait sur le site web des dveloppeurs (http://developer.apple.com). Le processus dinscription et de prparation aux tests rels est dtaill en annexe.

Une petite prsentation


Les lments de base
Pour dvelopper une application logicielle, nous avons besoin des lments suivants :
j

Un langage de programmation ; pour dvelopper sur liPhone OS, ce sera Objective-C. Des outils de dveloppements (diteur, compilateur, composition de linterface graphique, dbogueur, etc.) : nous utiliserons principalement XCode et Interface Builder. Une bibliothque dAPI (Application Programming Interface) permettant au code crit dans le langage de programmation daccder aux fonctions fournies par le systme dexploitation ; sur les systmes Mac OS X et iPhone OS, ces bibliothques se nomment des frameworks. Si vous tes familier de la terminologie PC/Windows, les DLL sont lquivalent des frameworks.

Nous commencerons notre tude par la dcouverte des outils XCode et Interface Builder et du langage Objective-C puis nous aborderons progressivement les diffrents frameworks diPhoneOS. Vous avez vraisemblablement dj entendu parler de Cocoa Touch. Il sagit de la partie de liPhone OS que nous utiliserons le plus souvent tout au long de notre parcours. Cocoa Touch est compos de 2 frameworks :
j

UIKit prend en charge la gestion de linterface utilisateur (UI pour User Interface) :

diffrents lments de linterface utilisateur (boutons, champs de texte, etc.) ; gestion des vnements (tapes et gestes) ; fonctionnement gnral des applications.

14

Introduction

Foundation contient des classes utilitaires et des interfaces de haut

niveau vers les fonctions du systme : classes de collection (tableaux, ensembles et dictionnaires) ; classes utilitaires (dates, chanes de caractres, etc.) ; accs vers le gestionnaire de chiers, les fonctions graphiques, laccs au rseau, etc.

Spcicits du dveloppement sur iPhone/ iPod touch/iPad


Le dveloppement dapplication pour iPhone OS prsente peu de difficults ; il existe de nombreux points communs avec le dveloppement pour un ordinateur. Il faudra cependant tenir compte des limitations technologiques de ces objets patants : cran de petite taille, ncessit dconomiser lnergie, limitation de la mmoire. Quelques consquences de ces limitations sont dtailles ci-aprs :

Une seule application sexcute un instant donn (si lon excepte le systme dexploitation) ; la premire consquence est quil est impossible de crer une application qui tourne en tche de fond. Une seule fentre est affiche lcran. Chaque application possde un bac sable (sandbox), un systme de chiers priv qui contiendra toutes ses donnes (chiers de paramtres et chiers de donnes) ; il est impossible deux applications daccder au mme chier et donc dchanger leur virus. La taille dcran est limite 480 x 320 pixels sur iPhone et iPod Touch, et 1024 x 768 pixels sur iPad. La taille de RAM dun iPhone est de 128 Mo, approximativement la moiti de cette mmoire est utilise par lOS ; lapplication en cours dexcution doit se contenter denviron 64 Mo, il faudra conomiser la mmoire.

j j

Langage Objective C
Objective-C est le langage de programmation "naturel" sur iPhone OS et aussi sur Mac OS X. Il est vrai que ce langage est rarement utilis sur dautres plateformes mais prsente de nombreuses simi-

Une petite prsentation

15

larits avec le langage Java plus largement employ. Objective-C est une extension "objet" du langage C, au mme titre que C++, mais beaucoup plus simple que celui-ci et plus facile apprendre.

Pour aller plus loin


Ce livre vous expliquera toutes les techniques fondamentales mises en uvre dans les frameworks de liPhone OS. Il vous donnera les cls qui vous permettront de continuer votre exploration et de dvelopper des applications dont la seule limite sera votre imagination.

Do you speak English ?


Ou plutt, Do you read english ? Pour aller plus loin, il vous faudra exploiter la riche documentation dApple celle intgre lenvironnement de dveloppement et celle disponible sur le site des dveloppeurs. Cette documentation est en anglais. Ce sera donc un atout si vous tes laise avec la langue de Shakespeare.

Tout nest pas perdu


Si vous tes allergique langlais, tout nest pas perdu. Pour aller plus loin, il sera alors indispensable de vous inscrire sur un forum de dveloppeurs franais o vous trouverez toujours une bonne me pour vous aider et vous transmettre son savoir, par exemple http: //forum.macbidouille.com ou www.pommedev.com.

Les applications que nous dtaillerons


Au fur et mesure de notre parcours dans les frameworks de liPhone, nous dvelopperons quelques applications. Vous pourrez les utiliser telles quelles sur votre iPhone et mme les amliorer. En voici la liste :
j j j j

HelloWorld graphique ;

Convertisseur de monnaie ; Prts aux amis ; Dtecteur de verticale.

Bonne exploration !

16

Introduction

PREMIERS PAS

Crer un projet avec XCode .................................................................................... 19 Composer linterface utilisateur ........................................................................... 25 Tester lapplication ...................................................................................................... 28 Finaliser lapplication ................................................................................................. 30 Agrmenter lapplication ......................................................................................... 34 Challenge ........................................................................................................................ 36 Check-list ......................................................................................................................... 38

17

CHAPITRE 1

Dans ce chapitre, nous crerons notre premire application. Comme le veut la tradition, il sagira dun "Hello World". Rien de trs spectaculaire donc mais ce sera loccasion de prendre en main les trois outils fondamentaux du SDK : XCode, Interface Builder et iPhone Simulator, le simulateur diPhone et diPad.

1.1. Crer un projet avec XCode


Lancer XCode
XCode est lapplication qui va nous permettre de :
j j j

grer nos projets ; grer et diter les chiers de code source ; construire et tester nos applications.

Un projet est lensemble des donnes ncessaires pour construire une application :
j j j j

code source ; ressources (images, sons, etc.) ; liste des frameworks utiliss ; informations complmentaires (chier dinformation, paramtrage de la construction, etc.).

Pour crer un projet, il faut dabord lancer lapplication XCode. Linstallation standard du SDK place cette application dans le dossier /Developer/Applications. Double-cliquez sur licne XCode.

Figure 1.1 : Localisation de lapplication XCode

1.1. Crer un projet avec XCode

19

Si cest la premire fois que vous lancez XCode, la fentre daccueil apparat lcran. Vous pouvez fermer cette fentre.

Figure 1.2 : Fentre daccueil de XCode

Accder plus facilement XCode


Vous aurez vous servir intensment de XCode. Il sera plus pratique davoir lapplication disposition rapidement en la gardant dans le Dock.

Figure 1.3 : Garder XCode dans le Dock

Crer un projet
Procdez ainsi : 1 Sous XCode, activez la commande New Project du menu File. Vous pouvez galement cliquer sur Create a new Xcode project dans le panneau daccueil.

20

1. Premiers pas

Figure 1.4 : Cration dun projet

LAssistant New Project saffiche, vous permettant de choisir le type de projet que vous souhaitez crer.

Figure 1.5 : Assistant Nouveau Projet

1.1. Crer un projet avec XCode

21

XCode prend en charge plusieurs types de projet. Lorsquon cre un projet, il faut choisir le bon modle. An de vous faciliter le choix, la partie gauche de lAssistant prsente les groupes de modles. Dans la suite de louvrage, nous choisirons toujours le groupe Application pour iPhone OS. 2 Slectionnez View-based Application, vriez que le menu droulant Product est bien slectionn sur iPhone et cliquez sur le bouton Choose.

Les autres modles dapplication


Nous verrons les autres modles dapplications dans la suite de cet ouvrage.

3 Un panneau saffiche qui vous permet de nommer le projet en cours de cration. Saisissez HelloWorld dans la zone de texte Save As puis cliquez sur le bouton Save.

Figure 1.6 : Panneau de sauvegarde

22

1. Premiers pas

Le dossier de projet
XCode cre un dossier, du mme nom que le projet, et y insre les chiers composant le projet. Ce dossier recevra vos propres chiers (images, icones, ). Il est cr par dfaut dans votre dossier Documents. Vous pouvez choisir un autre emplacement avant de cliquer sur le bouton Save.

ce stade, nous avons cr le dossier de projet et la fentre de projet de XCode saffiche.

Grer le projet
La fentre de projet permet de grer tous les lments dun projet.

Figure 1.7 : La fentre de projet

Cette fentre est compose des lments suivants :


j j

une barre doutils en haut ; la zone des Groupes et Fichiers (Groups and Files) sur la partie gauche de la fentre, qui structure les diffrentes informations et les chiers composant le projet ; la Vue Dtaille au centre de la partie droite de la fentre, dans laquelle on peut visualiser les attributs principaux de chacun des composants du projet ;

1.1. Crer un projet avec XCode

23

une Zone ddition en bas de la partie droite de la fentre qui nous permettra dditer les chiers du projet (cest dans cette zone que nous saisirons le code source de lapplication) ; une Barre dtat en bas de la fentre ; nous y lirons les messages mis par XCode lors de la construction de lapplication.

Structure mais pas sous-dossiers


Les chiers sont rpartis sous XCode en Classes, Autres Sources, Ressources, etc. Cette structuration est indpendante de la faon dont les chiers sont structurs en sous-dossiers dans le dossier du projet ; par dfaut, seul un sous-dossier Classes est cr ; tous les autres chiers sont " plat" dans le dossier du projet.

Nous verrons lutilisation de ces diffrentes parties dans la suite du livre. Pour lheure, et si ce nest pas dj le cas, slectionnez HelloWorld dans la zone des Groupes et Fichiers pour afficher la liste de tous les chiers du projet dans la Zone Dtaille. XCode a cr pour nous les chiers suivants :
j

Les chiers de type .framework sont des liens vers les frameworks diPhone OS ncessaires pour notre application HelloWorld :
CoreGraphics.framework pour les fonctions de base de laffichage graphique ; Foundation.framework pour les accs aux fonctions de base du systme (chiers, rseau, etc.) ; UIKit.framework qui contient toutes les classes dobjet de base pour crer une application sous Cocoa Touch (boutons, champs

de texte, etc.).
j

HelloWorld-Info.plist est le chier des proprits de lapplication ; nous utiliserons bientt ce chier. HelloWorld.app est notre application. Son nom apparat en rouge pour signaler que lapplication nest pas encore cre. Les chiers de type .pch sont des chiers intermdiaires dans le processus de construction de lapplication ; nous ne nous en occuperons pas. Les chiers .m (chier des dnitions) et .h (chiers des dclarations) contiennent les codes source Objective-C de lapplication :

24

1. Premiers pas

main.m linstar de main.c en langage C contient le code de la fonction main excute au lancement de lapplication ; nous naurons gnralement pas modier ce chier. HelloWorldAppDelegate.h et HelloWorldAppDelegate.m contiennent le code source du Dlgu de lapplication.

et HelloWorldViewController.m contiennent le code source du Contrleur de la Vue principale de lapplication. Ces chiers sont crs par XCode car nous avons utilis le modle View-based Application la cration du projet.
HelloWorldViewController.h
j

Les chiers de type .xib sont des chiers NIB.

Les Dlgus et les Contrleurs sont des motifs de conception (Design Pattern) abondamment utiliss dans la programmation Cocoa Touch et que nous expliquerons trs bientt. Les chiers NIB contiennent des objets prts lemploi, endormis en quelque sorte, qui sont rveills lorsque le chier est charg dans lapplication. Linterface utilisateur en particulier est dnie dans les chiers NIB, cest pourquoi ces derniers sont dits avec loutil Interface Builder. Dcouvrons sans plus tarder cet outil.

1.2. Composer linterface utilisateur


Sous XCode, vriez que dans le menu overview de la barre doutils, la valeur Active SDK est bien positionne sur iPhone Simulator 3.1.3.

Figure 1.8 : Activation du SDK pour le simulateur diPhone

Vous modierez la valeur du SDK actif pour tester votre application dans diffrents environnements :
1.2. Composer linterface utilisateur

25

j j j j

Simulator 3.1.3 pour tester sur le simulateur diPhone ; Simulator 3.2 pour tester sur le simulateur diPad ; Device 3.1.3 pour tester sur un iPhone ou iPod Touch rels ; Device 3.2 pour tester sur un iPad rel.

1 Sous XCode, double-cliquez sur le chier HelloWorldViewController.xib dans la Zone Dtaille de la fentre de projet ; Interface Builder se lance.

Figure 1.9 : Interface Builder

2 Trois fentres apparaissent. De gauche droite : une fentre dont le titre est le nom du chier NIB que lon vient douvrir, cest le contenu du chier NIB ; une fentre dans laquelle nous composerons la Vue (View) de notre interface utilisateur ; une fentre Library qui contient les objets que nous utiliserons pour composer linterface utilisateur. 3 Cherchez lobjet Label dans la fentre Library et faites-le glisser sur la Vue de notre projet (voir Figure 1.10). 4 Slectionnez le Label nouvellement dpos sur la Vue an de le positionner o vous souhaitez (voir Figure 1.11).

26

1. Premiers pas

Figure 1.10 : Objet Label dans la fentre Library

Figure 1.11 : Label positionn sur la Vue principale de lapplication

1.2. Composer linterface utilisateur

27

Double-cliquez sur le Label pour slectionner le texte et saisissez HelloWorld. Enregistrez le chier (commande Save du menu File), puis revenez dans XCode et cliquez sur le bouton Build and Run de la barre doutils pour construire et lancer lapplication.

6 Il est possible quune bote de dialogue apparaisse pour signaler que nous navons pas enregistr tous les chiers que nous avons modis. Cliquez alors sur le bouton Save All.

Figure 1.12 : Sauvegarder les chiers modis

Lapplication HelloWorld est construite par XCode et lance dans le simulateur diPhone

1.3. Tester lapplication


iPhone Simulator est loutil qui nous permet de tester les applications

sur Mac. Il sagit de la premire tape de test. Bien sr, il faudra tester lapplication sur des appareils rels avant de la diffuser au public. Le test sur simulateur est intressant ; il permet de dboguer plus facilement lapplication (voir Figure 1.13). Explorez les menus du simulateur. On peut basculer et mme secouer virtuellement lappareil. Une caractristique intressante est la possibilit de tester rapidement notre application sur des versions diffrentes diPhone OS : menu Matriel, sous-menu Version. Explorez galement le simulateur, comme si vous utilisiez votre iPhone (cliquez sur le gros bouton en bas de liPhone an de revenir lcran daccueil). Les applications Photos, Contacts et Safari fonctionnent normalement ; on pourra ainsi tester les applications utilisant les photos et les contacts de liPhone.
28

1. Premiers pas

Figure 1.13 : Simulateur diPhone

Gestes avec 2 doigts


Les gestes avec 2 doigts sont simuls en maniant la souris tout en pressant la touche [Alt] du clavier. Essayez avec lapplication Safari.

Vous pouvez aussi lancer votre application sur le simulateur diPad en slectionnant le SDK iPhone Simulator 3.2 sous XCode.

Figure 1.14 : Simulateur diPad

En explorant le simulateur, vous verrez que le logo permettant de lancer notre application HelloWorld est un carr blanc. Nous amliorerons cela immdiatement.

1.3. Tester lapplication

29

Figure 1.15 : Application sans logo

1.4. Finaliser lapplication


Nous allons maintenant ajouter un logo notre application HelloWorld.

Revenez dans lapplication XCode et choisissez sur votre ordinateur limage que vous souhaitez utiliser comme logo. Il est recommand de choisir une image carre au format PNG.

Changer dapplication
Sur Mac OS X, on peut changer rapidement dapplication par la combinaison de touches X+[].

Lajout du logo se fait en deux temps : 1 Ajoutez limage au projet. 2 Dclarez cette image comme tant le logo de lapplication.

Ajouter un chier au projet


1 Dans XCode, slectionnez Resources dans HelloWorld dans la zone Groupes et Fichiers de la fentre du projet et activez la commande Add to project du menu Project. Le panneau standard de Mac OS X permettant de choisir un chier saffiche. 2 Recherchez limage dsire laide de ce panneau et cliquez sur le bouton Add.

30

1. Premiers pas

Figure 1.16 : menu Project de XCode

Un panneau saffiche pour que vous puissiez prciser la faon dont vous souhaitez ajouter le chier au projet.

Figure 1.17 : Ajout dun chier au projet

Lorsque la case Copy items into destination groups folder de ce panneau est coche, le chier slectionn est copi dans le dossier du projet et rang dans le groupe slectionn (en loccurrence Resources).

1.4. Finaliser lapplication

31

3 Cochez cette case. Par dfaut, la case HelloWorld est coche dans la liste Add To Targets. Cela signie que le chier que nous ajoutons sera copi dans le dossier des ressources de lapplication HelloWorld lors de la construction. 4 Laissez cette case coche et cliquez sur le bouton Add. 5 Limage apparat dans la liste des chiers du projet. Slectionnez ce chier dans la zone groupes et chiers pour vrier son contenu dans la zone ddition.

Figure 1.18 : Limage est ajoute au projet

Vous savez maintenant ajouter un chier un projet. Vous procderez exactement ainsi chaque fois que vous aurez besoin dajouter une image, une vido, un son ou tout autre chier un projet.

Dclarer le logo de lapplication


Il faut maintenant indiquer que limage que nous venons dajouter doit tre utilise comme logo de lapplication HelloWorld. 1 Toujours sous XCode, slectionnez le chier HelloWorld-Info.plist dans le groupe Resources. Ce chier contient les proprits de lapplication ; le logo est une de ces proprits. Lorsque le chier est slectionn, son contenu apparat dans la zone ddition.

32

1. Premiers pas

2 Slectionnez la zone de texte ct de la proprit Icon File et saisissez-y le nom du chier contenant le logo.

Figure 1.19 : Nom du chier contenant le logo

3 Cliquez sur le bouton Build and Go de la barre doutils de XCode. Si votre application est toujours en train de sexcuter dans le simulateur, une bote de dialogue saffiche pour vous prvenir et vous demander si vous souhaitez arrter lexcution en cours. Cliquez sur OK.

Figure 1.20 : Arrter lexcution en cours

1.4. Finaliser lapplication

33

4 Le cas chant, acceptez denregistrer les chiers modis (vous venez de modier HelloWorld-Info.plist). Lapplication sexcute sur le simulateur diPhone. Cliquez sur le gros bouton du simulateur pour vrier votre logo.

Figure 1.21 : HelloWorld avec logo

1.5. Agrmenter lapplication


Nous nallons pas nous arrter en si bon chemin. Nous agrmenterons notre application par une illustration car pour linstant, elle est un peu triste. Choisissez une autre image et ajoutez-la au projet HelloWorld sous XCode.

34

1. Premiers pas

Reportez-vous la section prcdente si vous ne vous souvenez plus comment on ajoute un chier au projet.

Figure 1.22 : Une nouvelle image est ajoute au projet

Mettre notre image dans la vue


Pour rendre visible cette image lors de lexcution de lapplication, il faut retourner sous Interface Builder an de modier linterface utilisateur. 1 Dans la fentre Library dInterface Builder, cliquez sur le bouton Media pour obtenir la liste de tous les chiers de type media (Image, Vido ou Son) de votre projet.

Figure 1.23 : Media du projet disponible sous Interface Builder

1.5. Agrmenter lapplication

35

2 Faites glisser limage souhaite sous lobjet Label laide de la souris. Si vous faites attention pendant ce positionnement, vous verrez apparatre des lignes pointilles de couleur bleue. Ces lignes de positionnement vous aide aligner lobjet que vous tes en train de dplacer.

Figure 1.24 : Application avec un Label et une Image

Image au lancement de lapplication


Si votre projet contient une image dont le nom est Default.png, cette image sera automatiquement pendant le lancement de lapplication. Nous nous en souviendrons lorsque nous btirons des applications un peu longues au dmarrage.

1.6. Challenge
Avant de passer au chapitre suivant, nous vous invitons modier les attributs graphiques des objets Label et Image de notre interface utilisateur an de dcouvrir les diffrentes possibilits. Pour modier les attributs dun objet : 1 Activez linspecteur laide du menu Tools sous Interface Builder et slectionner le premier onglet de la fentre Inspecteur.

36

1. Premiers pas

2 Slectionnez lobjet sur lequel vous souhaitez travailler pour en visualiser les attributs dans linspecteur et les diter.

Figure 1.25 : Menu Tools dInterface Buider

Figure 1.26 : Inspection des attributs de lobjet Label

1.6. Challenge

37

1.7. Check-list
Nous venons de terminer notre premire application pour iPhone. Pour cela, nous avons utilis :
j

XCode an de :

crer un projet ; ajouter des chiers au projet ; modier les proprits de lapplication ; construire lapplication ; lancer son excution dans le simulateur.
j

Interface Builder an de :

composer linterface utilisateur ; ajouter un media linterface utilisateur.


j

Et le simulateur diPhone pour tester notre application.

Au passage, nous remarquons que cette ralisation a t obtenue sans saisir une seule ligne de code Objective-C. Cest le rsultat dune caractristique intressante du framework Cocoa Touch et des modles dapplications de XCode ; chaque modle permet de construire une application qui fonctionne sans modication, le dveloppeur se concentre sur lcriture du code pour le comportement quil veut ajouter. Notre application HelloWorld est imparfaite car nous ne pouvons pas interagir avec elle. Notre prochaine production sera plus satisfaisante et nous permettra dcrire nos premires lignes de code.

38

1. Premiers pas

INTERACTIONS SIMPLES
Programmation oriente objet .............................................................................. 41 Mcanisme Cible-Action .......................................................................................... 44 Hirarchie des classes de Convertisseur1 ........................................................ 60 Manipulation des objets en Objective-C ........................................................... 63 Check-list ......................................................................................................................... 73

39

CHAPITRE 2

Notre objectif dans ce chapitre sera de raliser une application pour notre prochain voyage aux tats-Unis. Nous voulons connatre lquivalent en euros des prix exprims en dollars. La premire version de notre application se prsentera ainsi. Nous la perfectionnerons ensuite.

Figure 2.1 : Application Convertisseur1

Vous devrez dabord patienter car il faut que vous compreniez ce quest la programmation oriente objet.

2.1. Programmation oriente objet


La programmation oriente objet est un style de programmation qui permet damliorer la testabilit, de faciliter la maintenance et donc de produire des logiciels de meilleure qualit aux fonctionnalits sont plus complexes. Nous nexposerons pas ici la thorie de la POO (Programmation oriente objet). Notre ambition se limitera comprendre comment nous utiliserons cette thorie dans le langage Objective-C, langage objets, et avec les frameworks de Cocoa Touch, qui contiennent les objets prdnis dont nous aurons besoin. La terminologie POO employe sera celle du dveloppement pour iPhone OS.

2.1. Programmation oriente objet

41

Nous traiterons ici les notions lmentaires ; dautres notions plus avances seront voques plus loin.

Objets
Un objet Objective-C permet de reprsenter un objet du monde "rel" ou manipulable par lutilisateur. Par exemple, un label ou une image sur une interface sont des objets, lapplication que nous dveloppons est un objet, et nous aurons besoin plus loin de crer nos propres objets : un livre prt, une monnaie convertir, etc. Les objets dun langage de programmation comprennent :
j

un tat, cest--dire la situation de lobjet un moment donn de sa vie. Par exemple ltat dun objet bouton pourrait contenir ; sa position sur la fentre ; limage actuellement affiche ; limage afficher si lon clique sur le bouton, etc.

un comportement, cest--dire toutes les actions dont lobjet est capable : cliquer sur un bouton (ou toucher le bouton pour se conformer la terminologie iPhone OS).

Figure 2.2 : Reprsentation dun objet

Objets du langage Objective-C


Un objet comprend des variables dinstance et des mthodes. Les variables dinstance permettent de reprsenter ltat de lobjet, et les mthodes permettent de reprsenter son comportement.

42

2. Interactions simples

Ne vous inquitez pas si vous ne comprenez pas tout de suite les subtilits induites par cette dnition ; cela viendra avec la pratique. Les variables dinstance sont des variables du langage Objective-C. On peut galement utiliser des variables du langage C puisque Objective-C en est une extension. Pourquoi parle-t-on dinstance ? Simplement pour prciser la porte de la variable ; elle est accessible uniquement depuis lune des mthodes de lobjet (linstance) et inaccessible depuis "lextrieur" de lobjet.
Si vous avez besoin de vous rafrachir la mmoire ou dapprendre les bases du langage C, reportez-vous lannexe B.

Classes
Les informaticiens emploient rarement le terme Objet car il est ambigu (et les informaticiens naiment pas lambigut), ils emploient les termes Classe ou Instance. Une classe est un modle qui permet de reproduire des instances. La classe est un type dobjet, linstance est un objet particulier de ce type.

Figure 2.3 : Une classe et 2 instances du mme type

Classe
Une classe est un modle (type) dobjet qui permet de dnir les variables dinstances et les mthodes qui devront exister pour toutes les instances de cette classe.

2.1. Programmation oriente objet

43

Chose1 et Chose2 sont deux instances de la classe Chose. Chaque instance possde ses propres variables dinstance, mme si elles ont le mme nom dni par la classe.

Messages
Lorsquune mthode est excute, elle doit pouvoir accder aux variables dinstance de lobjet. Il faut donc que le programmeur prcise, lorsquil crit son programme, sur quelle instance il veut excuter cette mthode. On dit que le programmeur envoie un message lobjet.

Message
Un message est la demande transmise une instance pour excuter une mthode particulire dans le contexte de linstance (en utilisant les variables dinstances lui appartenant).

Rcepteur
Le rcepteur dun message est lobjet qui reoit le message.

Aprs cet intermde dexplications thoriques, voyons comment on utilise ces concepts pour programmer sous Cocoa Touch, en commenant par le mcanisme cible-action.

2.2. Mcanisme Cible-Action


Nous allons mettre en pratique immdiatement le mcanisme cibleaction en dveloppant notre application Convertisseur1. La copie dcran en dbut de chapitre montre le rsultat auquel nous voulons arriver :
j

un champ de texte dans lequel lutilisateur saisit le montant en dollars ; un champ de texte dans lequel lutilisateur peut lire le rsultat de la conversion du montant en euros.

Nous souhaitons que la conversion soit ralise pendant que nous inscrivons le montant en dollars ; la valeur en euros doit tout instant tre le rsultat de la conversion de la valeur en dollars. Nous avons donc besoin de trois objets :
44

2. Interactions simples

j j

2 instances de la classe UITextField pour les champs de texte ; 1 objet charg de faire la conversion.

Figure 2.4 : Structure des objets pour lapplication Convertisseur1

Lobjet charg deffectuer les conversions sera une instance de la classe Convertisseur1ViewController ; nous verrons pourquoi dans un instant.

Crer les outlets


Notre Convertisseur1ViewController a besoin de connatre les deux champs de texte puisquil faudra quil "lise" la valeur en dollars et quil "crive" la valeur en euros. Il a donc besoin de 2 variables dinstance de type "instance de classe UITextField". 1 Ouvrez XCode et crez un projet de type View-based Applicationcomme au chapitre prcdent. 2 Intitulez ce projet Convertisseur1 ; ce sera notre premire version du Convertisseur de monnaies. 3 Slectionnez le chier Convertisseur1ViewController.h dans la fentre de projet et modiez son contenu, dans la zone ddition, pour obtenir le texte suivant :
#import <UIKit/UIKit.h> @interface Convertisseur1ViewController : UIViewController { IBOutlet UITextField *labelDollar; IBOutlet UITextField *labelEuro; } @property (retain,nonatomic) UITextField *labelDollar; @property (retain,nonatomic) UITextField *labelEuro; @end

2.2. Mcanisme Cible-Action

45

Nous venons de dnir deux variables dinstance, labelDollar et labelEuro de type UITextField pour les instances de la classe Convertisseur1ViewController. La ligne de code IBOutlet UIText Field *labelDollar; signie que labelDollar est une variable de type UITextField * (les adeptes du C liront "est un pointeur sur une structure de type UITextField") et que de plus, cette variable est un outlet (dclar par IBOutlet). Quest-ce quun outlet ? Cest simplement le moyen de dire Interface Builder que lon souhaite connecter cette variable dinstance ; nous allons expliquer cela. Au passage, notons que le "IB" de IBOutlet signie Interface Builder.

Outlet
Un outlet est une sorte de variable dinstance, cest un pointeur vers un autre objet. Un outlet est congurable laide dInterface Builder.

Aprs avoir saisi les quelques lignes de code prcdentes dans le chier Convertisseur1ViewController.h, licne de ce dernier est grise dans la fentre de projet de XCode. Les icnes grises signalent les chiers qui ont t modis.

Figure 2.5 : Fichier Convertisseur1ViewController.h modi

4 Sauvegardez le chier que lon vient de modier soit par la combinaison de touches X+[S], soit en choisissant la commande Save du menu File sous XCode.

46

2. Interactions simples

Cliquez dans la zone ddition


Pour sauvegarder un chier sous XCode, il faut quil soit slectionn et il faut cliquer dans la zone ddition de la fentre de projet.

Prparer linterface utilisateur


1 Double-cliquez sur le chier Convertisseur1ViewController.xib dans la fentre de projet sous XCode ; Interface Builder se lance. 2 Prparez linterface utilisateur de lapplication Convertisseur1 laide de 3 labels et de 2 champs de texte (Text Field).

Figure 2.6 : Interface utilisateur de Convertisseur1

Figure 2.7 : Champ de texte

2.2. Mcanisme Cible-Action

47

3 Si vous souhaitez que votre interface ait exactement le mme aspect, utilisez linspecteur pour modier les attributs graphiques des objets conformment au tableau.
Tableau 2.1 : Configuration des objets de linterface Champ Montant en dollars Montant en euros Type Police Helvetica 17 Helvetica 17 Couleur Couleur par dfaut Couleur par dfaut Couleur par dfaut Convertisseur de Monnaies Label Helvetica Bold Oblique 24 Grape

Label Label

Text Field Helvetica 17

Rappelez-vous ; pour modier les attributs dun objet, on utilise linspecteur aprs avoir slectionn lobjet que lon veut modier.

Figure 2.8 : Attributs du label de titre

4 Cliquez sur la description de lattribut Font pour afficher la fentre ottante Fonts. Il faut cliquer sur la case de couleur Color-Text pour afficher la fentre ottante Colors (voir Figure 2.9).

Slection multiple
Vous pouvez slectionner simultanment plusieurs objets graphiques du mme type (label ou text field) an den modier les attributs graphiques en une fois avec linspecteur. Cliquez sur le premier objet puis cliquez sur les suivants en maintenant la touche [Maj] enfonce pour tendre la slection.

48

2. Interactions simples

Figure 2.9 : Fentres ottantes dattributs graphiques

Pour naliser notre interface, nous allons indiquer que nous souhaitons que le clavier numrique saffiche lorsque lutilisateur touchera le champ de texte pour saisir le montant en dollars convertir. 5 slectionnez ce champ de texte sur la vue et choisissez Numbers & Punctuation dans la liste droulante pour loption Keyboard dans linspecteur . Maintenant que notre interface utilisateur est termine, nous pouvons connecter les outlets de notre application aux objets que nous venons dagencer.

Figure 2.10 : Choix du clavier pour un champ de texte

2.2. Mcanisme Cible-Action

49

Connecter les outlets


1 Toujours sous Interface Builder, slectionnez Files Owner dans la fentre du contenu du chier NIB puis slectionnez longlet Connections de linspecteur (le deuxime onglet en partant de la gauche).

Figure 2.11 : Slection de Files Owner

Nous dcouvrons dans linspecteur les deux outlets que nous avons ajouts dans le chier Convertisseur1ViewController.h. 2 Pour connecter un outlet un objet de linterface utilisateur, effectuez un cliquer-glisser-relcher allant du petit cercle droite de loutlet dans linspecteur jusqu lobjet que vous souhaitez rattacher.

Figure 2.12 : Connexion dun outlet un objet

3 Connectez loutlet labelDollar au champ de texte ct du label Montant en dollars puis connectez loutlet labelEuro au champ de texte ct du label Montant en euros.

Figure 2.13 : Les outlets connects 50


2. Interactions simples

Tester linterface
La combinaison de touches X+[R] sous Interface Builder provoque le lancement du simulateur diPhone pour visualiser linterface que nous venons de construire. Lapplication ne fonctionne pas mais nous pouvons activer tous les objets de linterface pour vrier leur comportement graphique.

Notre objet comprend 4 outlets alors que nous nen avons dni que 2. Les outlets supplmentaires sont obtenus par hritage. Nous tudierons ce concept important dans quelques pages. Pour le moment, nous terminons lapplication Convertisseur1.

Dclarer les actions


Nous avons construit linterface utilisateur de notre application Convertisseur1, nous lui avons indiqu comment communiquer avec le cur de lapplication en dnissant des outlets et en tablissant les connexions. Il nous faut maintenant dnir prcisment le comportement de lapplication. Revenez dans XCode et compltez le chier Convertisseur1
ViewController.h de la faon suivante :
#import <UIKit/UIKit.h> @interface Convertisseur1ViewController : UIViewController { IBOutlet UITextField *labelDollar; IBOutlet UITextField *labelEuro; } @property (retain,nonatomic) UITextField *labelDollar; @property (retain,nonatomic) UITextField *labelEuro; - (IBAction) changeValue; @end

Nous venons de dclarer une action dont le nom est changeValue.

Action
Une action est une mthode dinstance dont la vocation est dtre excute lorsquun vnement survient. Elle est congurable laide dInterface Builder.

2.2. Mcanisme Cible-Action

51

Nous souhaitons que cette action soit appele chaque fois que lutilisateur change le montant en dollar, et quelle calcule le montant en euros puis laffiche dans le champ adquat. La connexion entre laction et lvnement sera ralise laide dInterface Builder. Le comportement de laction est dcrit en Objective-C dans la dnition de laction.

Dnir les actions


Sauvegardez le chier Convertisseur1ViewController.h que nous venons de modier et, toujours sous XCode, ouvrez le chier Convertisseur1ViewController.m.

Dclaration et Dnition
linstar des langages C et C++, les dclarations et les dnitionssont spares en Objective-C. Par convention, une classe dobjets NomDeLaClasse est dcrite dans 2 chiers sources NomDeLaClasse.h et NomDeLaClasse.m.

Rgle de nommage des classes


An de faciliter la lecture du code source, il est dusage dadopter des rgles de nommage. En particulier, on essaiera de trouver un nom explicite ; il faut viter les noms abrgs (par exemple NdlC au lieu de NomDeLaClasse) ; ils nuiront la lisibilit et donc notre capacit modier le code dans lavenir. En Objective-C, le nom dune classe est une srie de mots accols et chaque mot commence par une majuscule y compris le premier mot, par exemple : NomDeLaClasse.

Le chier avec lextension .h contient la dclaration de la classe, interface en anglais, cest--dire tout ce qui est ncessaire pour utiliser une instance de cette classe ; le type et le nom de chaque variable dinstance et de chaque mthode. Le chier avec lextension .m contient la dnition de la classe, implementation en anglais, cest--dire le dtail du comportement de lobjet.

Encapsulation
Lencapsulation est le principe selon lequel on doit pouvoir utiliser un objet sans connatre le dtail de la faon dont cet objet travaille.

52

2. Interactions simples

Pour illustrer le principe dencapsulation, prenons un exemple : lorsque je veux dmarrer ma voiture je tourne la cl de contact et le moteur se met en marche ; jutilise linterface, cest simple. Imaginons tout ce que je devrais faire si je navais pas cette interface ; mettre en marche la pompe essence, rgler la richesse du mlange en fonction de la temprature du moteur, mettre le pignon du dmarreur en contact avec larbre du moteur, faire tourner le dmarreur pour lancer le moteur, activer les soupapes de faon synchronise avec la position des pistons et dans le mme temps injecter le mlange dans le moteur, dclencher les explosions dans les cylindres au bon moment (toujours en fonction de la temprature du moteur et enn expulser les gaz brls. Tous les objets, y compris les objets Objective-C, devraient tre aussi simples utiliser que ma voiture. Lencapsulation est importante pour faciliter la maintenance des applications. Lorsque nous sommes amens modier un objet, nous navons pas ncessairement besoin de modier tous les objets qui lutilisent ; nous pouvons changer de voiture, nous navons pas besoin de changer notre faon de la dmarrer.

Inclusion des dclarations


Vous navez peut-tre pas fait attention mais nous avons dj utilis le principe dencapsulation. Dans notre chier Convertisseur1ViewController.h, nous employons les noms prdnis IBOutlet, IBAction, UIViewController et UITextField. O sont dnis tous ces noms ? Dans le framework UIKit diPhone OS. Comment indique-t-on quil faut utiliser ce framework ? La premire instruction du chier indique quil faut employer les dclarations du framework UIKit : #import <UIKit/UIKit.h>.

#import
#import demande au compilateur dinclure un chier dans le chier courant. Cette instruction est utilise principalement an de rcuprer les dclarations ncessaires pour employer un framework ou des objets dnis ailleurs.

Syntaxe :
Fichier global

#import FichierAInclure

Le chemin daccs au chier inclure doit tre mis entre crochets lorsquil se situe dans la bibliothque des frameworks diPhone OS. Par exemple, #import <UIKit/UIKit.h>.

2.2. Mcanisme Cible-Action

53

Fichier local

Le nom du chier inclure doit tre mis entre guillemets lorsquil se situe dans le mme dossier que le chier dans lequel il est inclus, par exemple : #import. "Convertisseur1ViewController.h"

Lorsque nous avons cr notre projet Convertisseur1 de type View-based Application, XCode a cr pour nous une classe Convertisseur1ViewController et ses 2 chiers .h et .m. Cest dabord dans cette classe que nous devons introduire le comportement de notre application et cest pourquoi nous modions les chiers Convertisseur1ViewController.h et Convertisseur1ViewController.m. Le chier .h sera inclus partout o ncessaire. Vous devinez o il faut linclure en tout premier lieu ? Dans le chier .m, bien sr ; cela permettra au compilateur de vrier que la dclaration et la dnition de notre classe sont cohrentes.

#import et #include
Les dveloppeurs C utilisent la clause #include. #import joue exactement le mme rle mais en vitant dinclure plusieurs fois le mme chier. UIKit.h, par exemple, est inclus dans presque tous les .h. Ds que lon inclut deux chiers .h dans le mme chier .m, on y inclut plusieurs fois le chier UIKit.h (les inclus de mes inclus sont mes inclus) ; le compilateur signalerait alors des erreurs car il naime pas que les mmes noms soient dclars plusieurs fois. La clause #import vite ce genre dinconvnient.

Regardez le contenu du chier Convertisseur1ViewController.m, XCode la prpar pour nous et il commence par linstruction #import "Convertisseur1ViewController.h".

Basculer entre dclaration et dfinition


Sous XCode, la combinaison de touches X+z+[] permet de basculer du chier .h vers le chier .m et rciproquement. Cette astuce est trs utile ; vous aurez souvent passer de lun lautre pendant la saisie du code source.

Il nous reste terminer notre classe Convertisseur1ViewController.

Dnition de laction changeValue


Si ce nest pas dj fait, slectionnez le chier Convertisseur1View Controller.m pour en visualiser le contenu dans la zone ddition de XCode. Modiez-le an dobtenir le code suivant :

54

2. Interactions simples

#import "Convertisseur1ViewController.h" @implementation Convertisseur1ViewController @synthesize labelDollar; @synthesize labelEuro; - (IBAction) changeValue { NSString *textDollar = labelDollar.text; float dollar = [textDollar floatValue]; float euro = dollar / 1.4908; NSString *textEuro = [[NSString alloc] initWithFormat: @"%.2f",euro]; labelEuro.text = textEuro; [textEuro release]; }

Lorsque vous saisissez ce code source (veillez le saisir trs prcisment tel que nous vous lindiquons) vous constatez que XCode vous propose de complter les mots au fur et mesure de la frappe. Cette fonctionnalit de XCode est la Terminaison de Code (Code Completion) et permet de gagner beaucoup de temps lors de la saisie de code source.

Saisie des crochets droits et des accolades


Les accolades { et } sont obtenues par les combinaisons de touches z+[(] et z+[)]. Les crochets droits [ et ] sont obtenus par les combinaisons de touches [Maj]+z+[(] et [Maj]+z+[)].

Utilisation de la Terminaison de Code


Lors de la saisie, si le mot propos par XCode vous convient, pressez la touche []. Sil ne vous convient pas, continuez la saisie ou pressez la touche [chap] an dobtenir une liste de suggestions. Vous pouvez alors slectionner le mot appropri.

Figure 2.14 : Suggestions de la terminaison de code

Nous comprendrons bientt de faon dtaille ces quelques lignes de code et leur syntaxe particulire, et vous serez mme capable dcrire la fonction changeValue en seulement une ou deux lignes.
55

2.2. Mcanisme Cible-Action

Nous avons prfr dcomposer les instructions pour vous aider en suivre la logique :
j

Les instructions @synthesize servent gnrer les accesseurs pour les proprits labelDollar et labelEuro. Laction changeValue est ensuite dnie par les instructions entre les accolades { et }, soit dans lordre : Un objet de type NSString est dclar et initialis avec la valeur crite par lutilisateur dans le champ de texte labelDollar. Un nombre de type oat est dclar et initialis avec le montant en dollars. (Nous avons besoin dun nombre de type oat pour faire notre calcul de conversion en euros car on ne peut pas effectuer de calculs sur un objet de type NSString.) Un nombre de type oat est dclar et initialis avec le montant converti en euros, avec un taux de conversion de 1,4908 $ pour 1 5 (cest le taux officiel la date de rdaction de ces lignes). Un objet de type NSString est cr et initialis avec une chane de caractres reprsentant le montant en euros, avec une prcision de 2 chiffres aprs la virgule. Le montant en euros est affich dans le champ de texte labelEuro, lutilisateur peut le lire.

Lobjet NSString textEuro est dtruit car chaque appel de changeValue, un nouvel objet est cr ; il faut viter les fuites de mmoire. Nous voyons ici lintrt davoir dni des outlets ; notre action changeValue peut "lire" et "crire" les contenus des champs de texte connects aux outlets. Comme cest notre premier bout de code, il nest pas certain que nous layons saisi correctement. Sous XCode, enregistrez le chier modi et construisez lapplication sans lancer lexcution.

Vrifier le code source


On peut vrier le code source de lapplication en la construisant sans lexcuter. Sous XCode, slectionnez la commande Build du menu Build ou tapez la combinaison de touches X+[B]. Par exemple, si nous avons saisi LabelEuro la place de labelEuro, lerreur nous est signale dans la barre dtat de la fentre de projet et dans le code source.

56

2. Interactions simples

Figure 2.15 : Erreur signale la construction

Vriez que votre code source ne contient pas derreurs et corrigez ces dernires ventuellement avant de passer ltape suivante.

Connecter les cibles


1 Retournez vers lapplication Interface Builder pour modier le chier Convertisseur1ViewController.xib. Slectionnez le champ de texte dans lequel nous aurons le montant en dollars et visualisez longlet Connections de linspecteur. Nous allons indiquer Interface Builder que nous souhaitons que laction changeValue du propritaire du chier Convertisseur1View Controller.xib (cest--dire une instance de la classe Convertisseur1View Controller) soit dclenche chaque modication, par lutilisateur, du contenu du champ de texte contenant le montant en dollar. Nous allons pour cela utiliser le mcanisme Cible-Action (Target-Action) de Cocoa-Touch. Pour mettre en uvre ce mcanisme nous avons besoin :
j

dun objet dont les vnements sont observs ; le champ de texte contenant le montant en dollars ; dun vnement qui va dclencher laction ; ici ce sera lvnement Editing Changed ;

2.2. Mcanisme Cible-Action

57

dun objet qui va recevoir laction la cible ; notre instance de la classe Convertisseur1ViewController ; dune mthode activer sur la cible laction ; la mthode changeValue.

2 Effectuez un cliquer-glisser-relcher allant du petit cercle droite de lvnement Editing Changed dans linspecteur jusqu lobjet Files Owner dans la fentre du contenu du chier NIB.

Figure 2.16 : Connexion dune cible

Une liste sur fond gris saffiche en surimpression sur la cible que nous avons slectionne. 3 Cliquez sur changeValue, lunique ligne de cette liste. Cette liste nous permet de choisir une action parmi celles dnies pour la cible. Comme nous avons dclar une seule action sur notre cible, la liste comprend une seule ligne.

Figure 2.17 : Liste des actions dnies sur la cible

4 Slectionnez nouveau Files Owner pour visualiser ses connexions dans linspecteur.

Figure 2.18 : Connexions de Files Owner

58

2. Interactions simples

Construire et tester lapplication Convertisseur1


1 Sauvegardez le chier NIB sous Interface Builder et revenez sous XCode pour construire et lancer lapplication (X+[R]). 2 Si la construction ne fonctionne pas correctement, vriez que le SDK actif est le simulateur et vriez votre code source.

Figure 2.19 : Vriez que le SDK actif est le simulateur

3 Testez votre application sur le simulateur diPhone. Nhsitez pas tout essayer : saisir des chiffres et des lettres, dans le champ des montants en dollars et dans celui des montants en euros, etc.

Figure 2.20 : Test de lapplication Convertisseur1

Nous nous rendons compte de tous les petits dfauts de notre application. Il faudra lamliorer avant de rellement lutiliser :
j

empcher que lutilisateur tape des lettres ;

2.2. Mcanisme Cible-Action

59

j j

pouvoir faire disparatre le clavier ; pouvoir effectuer les conversions dans les deux sens, des dollars en euros et vice-versa ; lorsquon revient dans lapplication, retrouver les montants tels quils taient lorsquon la quitte ; pouvoir modier facilement le taux de conversion.

Nous aborderons ces amliorations aprs avoir approfondi ce que nous venons de voir.

2.3. Hirarchie des classes de Convertisseur1


Vous tes sans doute un peu frustr car nous venons de crer une application mais vous navez sans doute pas compris tous les dtails du code que nous avons crit. Nous allons approfondir tout cela et vous comprendrez mieux le code de Convertisseur1 la n de ce chapitre.

Hritage
Notre classe Convertisseur1ViewController offre deux outlets supplmentaires que nous navons pas dclars. Ils appartiennent notre classe par hritage. Nous avons reprsent larbre dhritage des objets que nous avons manipuls pour notre application Convertisseur1 (voir Figure 2.21).
Convertisseur1ViewController hrite de ou "est une sorte de" UIViewController. En plus des variables dinstances et des mthodes que nous avons dnies pour Convertiseur1ViewController, ce dernier possde galement les attributs et le comportement de UIViewController ; en particulier les deux outlets supplmentaires que nous

avons vus prcdemment. Notre classe Convertisseur1ViewController contient, par hritage, tout le code des classes UIViewController, UIResponder et NSObject. Examinons plus attentivement la classe UITextField :
j

NSObject est la classe de base ; tous les objets doivent driver (doivent hriter) de NSObject. UIResponder ; un Rpondeur est un objet possdant la capacit de recevoir des vnements et de les traiter ou de les transmettre soit

60

2. Interactions simples

par le mcanisme Cible-Action, soit au rpondeur suivant dans la chane des rpondeurs. Nous expliquerons plus loin la chane de rpondeurs.

Figure 2.21 : Graphe dhritage de Convertisseur1


j

UIView ; une Vue est un objet qui apparat lcran et appartient la hirarchie des vues (voir ci-aprs). Une vue est galement un rpondeur puisquelle reoit et rparti les vnements crs par le systme lorsque lutilisateur touche cette vue sur lcran.

2.3. Hirarchie des classes de Convertisseur1

61

UIControl ; un Contrle est une vue particulire qui prsente une liste dvnements spciques et peut activer une action sur une cible pour chacun de ces vnements. UITextField ; un champ de texte est un contrle particulier (et donc aussi une Vue et un Rpondeur) qui permet lutilisateur de visualiser et modier une ligne de texte.

Et UILabel ? Vous devinez de quoi il hrite ? Rchissons Cest un objet, cela saffiche sur lcran, cest donc vraisemblablement une vue. Est-ce un contrle ? Peut-on congurer le mcanisme CibleAction partir dun UILabel ? Vous pouvez consulter longlet Connections de linspecteur sous Interface Builder, aprs avoir slectionn lun des deux labels de lapplication Convertisseur1, vous constaterez quaucun vnement nest dni pour un UILabel ; on ne peut pas dnir des Cibles-Actions pour un label. Donc UILabel hrite de UIView mais pas de UIControl.

Hirarchie des vues


Chaque application dun iPhone affiche une fentre unique qui occupe tout lcran. Une fentre est un objet de type UIWindow qui hrite de UIView (une fentre est un type particulier de vue). Cette fentre contient gnralement une vue qui elle-mme contient une ou plusieurs vues et qui, leur tour, peuvent contenir des vues, etc. La fentre et toutes les vues incluses constituent la hirarchie des vues. La hirarchie des vues peut voluer pendant lexcution de lapplication. Par exemple dans lapplication Contacts, lorsque lutilisateur passe de la liste des contacts la visualisation dune che des contacts, lapparence visuelle de linterface volue ; la hirarchie des vues a chang. Vous pouvez visualiser la hirarchie de vues de lapplication Convertisseur1 sous Interface Builder, dans la fentre du contenu du chier NIB. Cliquez sur le bouton du milieu de la rubrique View Mode. Cliquez sur le triangle ct de lobjet View pour visualiser son contenu (voir Figure 2.22). Il ny a pas de fentre de type UIWindow dans le chier Convertisseur1ViewController.h. La racine de la hirarchie est une vue dont le nom est View, elle contient les 5 labels et les 2 champs de texte que nous y avons ajouts. La fentre se trouve en fait dans le chier MainWindow.xib, vous pouvez ouvrir ce chier pour vous en convaincre.

62

2. Interactions simples

Figure 2.22 : Hirarchie des vues de Convertisseur1

Toutes les applications pour iPhone sont structures de la mme faon :


j

une fentre unique (UIWindow) qui restera affiche pendant toute lexcution de lapplication (elle est dcrite dans le chier MainWindow.xib) ; une ou plusieurs vues principales qui occupent chacune toute la fentre (chacune de ces vues est dcrite dans un chier NIB spcique).

Nous avons cr un projet de type View-based Application sous XCode pour construire notre application Convertisseur1. Ce type dapplication ne comprend quune vue principale, nous aurons loccasion de crer dautres types dapplication avec plusieurs vues principales.

2.4. Manipulation des objets en Objective-C


Aprs ces quelques lments thoriques, voyons comment on manipule les objets dans le langage Objective-C.

Dclaration
La dclaration dune classe seffectue dans un chier source qui porte le nom de la classe et dont lextension est .h. Par exemple MaClasse.h pour la classe MaClasse. Une dclaration suit toujours le mme schma :

2.4. Manipulation des objets en Objective-C

63

Une instruction @interface prcisant le nom de classe dclare et le nom de la classe dont elle hrite ; cette dernire est appele la superclasse de la classe en cours de cration. Toutes les classes doivent driver dune superclasse. Un bloc, dlimit par des accolades, contenant les dclarations de chaque variable dinstance de la classe. Les dclarations de chaque mthode de la classe. Linstruction @end pour indiquer la n du bloc @interface :
@interface MaClasse : SuperClasse { // dclaration des variables dinstance } // dclaration des mthodes @end

j j

Commentaires
Sur chaque ligne de code source, le texte partir de la double barre oblique "//", jusqu la n de la ligne, est considr comme un commentaire par le compilateur.

Dclaration des variables dinstance


Chaque variable dinstance a un nom et un type. Vous choisissez le nom de chaque variable ; cest ce nom que vous utiliserez pour employer cette variable. Bien sr, deux variables dinstances ne peuvent porter le mme nom.
type nom1, nom2, , nomN ;

On peut dclarer une ou plusieurs variables dans la mme instruction ; on utilise la virgule pour sparer les variables. Linstruction de dclaration se termine par un point-virgule.

Ne pas oublier le point-virgule


Loubli du point-virgule en n dinstruction est une erreur courante que mme les programmeurs conrms peuvent faire. Le point-virgule est le marqueur de n dinstruction du langage C et du langage Objective-C.

Vous pouvez utiliser :


j

Nimporte quel type dni dans le langage C (int, long, float, double, pointeur, etc.) ou un type labor laide des rgles du langage C (typedef).

64

2. Interactions simples

Un pointeur sur une classe dobjets, par exemple labelDollar de type UITextField * ; un pointeur sur une classe dobjet permet de manipuler les instances de cette classe ; Le type id, qui est un type prdni dans Objective-C, pointeur vers une classe non prcise ; on utilise le type id pour manipuler des instances dont on ne connat pas la classe.

Rgle de nommage des variables


Comme les classes, les variables doivent porter un nom explicite et il faut viter les noms abrgs (par exemple lD au lieu de labelDollar). En Objective-C, le nom dune variable est une srie de mots accols et chaque mot commence par une majuscule sauf la premire lettre qui reste minuscule, par exemple : labelDollar.

Dclaration des mthodes


Nous arrivons aux caractristiques dObjective-C les plus droutantes pour les programmeurs C ou C++ : la dclaration et lappel des mthodes. Commenons par le plus facile, la dclaration dune mthode qui na pas de paramtres :
// dclaration dune mthode dinstance - (type-de-la-valeur-de-retour) nomDeLaMethode ; // dclaration dune mthode de classe + (type-de-la-valeur-de-retour) nomDeLaMethode ;

Comme en C, le type est void si la mthode ne retourne pas de valeur. IBAction est quivalent void ; une action ne retourne pas de valeur.

Mthode dinstance / de classe


Une mthode dinstance sexcute dans le contexte dune instance de classe, elle accde aux variables propres cette instance. Lors de son excution, une mthode de classe nest pas attache une instance particulire ; elle ne peut accder aux variables dinstance.

Variables de classe ?
Contrairement dautres langages objet, il ny a pas de variables de classe en Objective-C, seulement des variables dinstance. Nous verrons comment nous en passer dans la suite de louvrage.

2.4. Manipulation des objets en Objective-C

65

Pour comprendre la dclaration des mthodes ayant des paramtres, nous allons dtailler un exemple :
- (void)getCharacters:(unichar *)buffer range:(NSRange)aRange ;

Cet exemple dclare une mthode dinstance :


j j j

dont le nom est getCharacters:range: ; qui ne retourne pas de valeur ; type de retour (void) ; dont le premier paramtre est de type pointeur sur un unichar unichar * (un unichar est un caractre Unicode) ; dont le second paramtre est de type NSRange (intervalle).

La mthode getCharacters:range: est une mthode dinstance de NSString qui permet dobtenir au format Unicode les caractres situs dans un intervalle donn dans la chane de caractre. Une mthode prend des paramtres lorsque son nom comprend des caractres deux-points, autant de paramtres que de caractres deux-points. Ceci est un peu droutant pour les programmeurs C ou C++ qui ont lhabitude de bien sparer le nom de la fonction de la liste des paramtres qui est mise entre parenthses. En Objective-C, on mlange. Vous verrez lusage que ce procd amliore la lisibilit du code ; le rle de chaque paramtre est identi.

Rgle de nommage des mthodes


En Objective-C, la rgle de nommage est identique pour les mthodes et les variables : une srie de mots accols et chaque mot commence par une majuscule sauf la premire lettre qui reste minuscule, par exemple : changeValue.

Accesseurs et Manipulateurs
En respect du principe dencapsulation, les variables dinstance appartiennent en propre chaque instance, elles sont accessibles uniquement par une mthode dinstance de la mme classe. Comment faire si lon a besoin de modier ltat dun objet ? (voir Figure 2.23) Le seul moyen pour accder depuis un objet A une variable dinstance appartenant un objet B, est de dnir des mthodes dinstance dans la classe de lobjet B pour cet usage. La mthode qui permet dobtenir la valeur dune variable dinstance est appeles accesseur (getter). La mthode qui permet de dnir la valeur dune variable dinstance est appele manipulateur (setter).

66

2. Interactions simples

Figure 2.23 : Les variables dinstances sont prives

Accesseur
La mthode permettant dobtenir la valeur dune variable dinstance est appele accesseur. Laccesseur porte le mme nom que la variable dinstance, son type de retour est le type de la variable dinstance et il ne prend pas de paramtre.

@interface MaClasse : SuperClasse { // dclaration dune variable dinstance typeVar varInstance } // dclaration de laccesseur de varInstance - (typeVar) varInstance ; @end

Manipulateur
La mthode permettant de dnir la valeur dune variable dinstance est appele manipulateur. Le nom du manipulateur est construit en mettant une majuscule au nom de la variable puis en le prxant par set. Le manipulateur ne retourne pas de valeur (void) et prend un unique paramtre du mme type que la variable dinstance.

@interface MaClasse : SuperClasse { // dclaration dune variable dinstance typeVar varInstance ; } // dclaration du manipulateur de varInstance - (void) setVarInstance: (typeVar) nouvelleValeur ; @end

2.4. Manipulation des objets en Objective-C

67

Nous verrons que les proprits permettent de dclarer et dnir plus facilement les accesseurs et les manipulateurs.

Dnition
La dnition dune classe seffectue dans un chier source qui porte le nom de la classe et dont lextension est .m, par exemple MaClasse.m pour la classe MaClasse :
j j j j

limportation du chier .h de la classe (clause #import) ; une instruction @implementation prcisant le nom de classe dnie ; les dnitions de chaque mthode de la classe ; linstruction @end pour indiquer la n du bloc @implementation :
#import "MaClasse.h" @implementation MaClasse // dfinition des mthodes @end

La dnition dune mthode :


j

commence par une ligne de code qui reprend la dclaration de la mthode sans le point-virgule la n ; se poursuit par un bloc dinstructions entre accolades.

Par exemple :
#import "Convertisseur1ViewController.h" @implementation Convertisseur1ViewController - (IBAction) changeValue { NSString *textDollar = labelDollar.text; float dollar = [textDollar floatValue]; float euro = dollar / 1.4908; NSString *textEuro = [[NSString alloc] initWithFormat: @"%.2f",euro]; labelEuro.text = textEuro; [textEuro release]; } @end

Messages
Nous savons maintenant dclarer et dnir une classe dobjets ; il sagit dun modle pour crer des instances dobjet. La programmation oriente objet consiste crer des objets, leur envoyer des messages puis les librer lorsque nous nen avons plus besoin (sur un iPhone, il faut conomiser la mmoire). Lorsquun objet reoit un message, il peut son tour crer des objets, leur envoyer des messages ou les librer, etc.
68
2. Interactions simples

La syntaxe pour envoyer un message un objet est la suivante : [objet appeldemthode]. objet est une variable dsignant linstance (pointeur sur linstance) si la mthode est une mthode dinstance ou le nom de la classe si cest une mthode de classe. appeldemethode est le nom de la mthode avec les paramtres utiliser. Par exemple, dans linstruction dollar = [textDollar floatValue];, la variable dollar prend pour valeur le retour de lappel de la mthode dinstance floatValue (qui ne prend pas de paramtre) sur linstance dsigne par textDollar. Ou encore, dans linstruction [window addSubview:myView];, la fentre dsigne par window reoit le message addSubview: avec le paramtre myView. Ce message ne retourne pas de valeur.

Proprits
Une proprit (property) est un attribut de lobjet auquel on peut accder par un accesseur et par un manipulateur. Gnralement, cet attribut est concrtis par une variable dinstance mais ce nest pas une obligation. Le langage Objective-C (plus prcisment partir de sa version 2.0) propose des mcanismes pour faciliter lemploi des proprits.

@property
La directive @property permet de dclarer laccesseur et le manipulateur dune proprit. Elle sutilise lendroit o lon aurait dclar ces mthodes. Il faut prciser le type et le nom de la proprit.
@property UITextField *labelDollar;

Dans cet exemple, nous dclarons une proprit labelDollar de type UITextField * (pointeur sur une instance de la classe UITextField). Cette dclaration est totalement quivalente aux deux dclarations :
- (UITextField *) labelDollar ; - (void) setLabelDollar: (UITextField *) newLabelDollar ;

@synthesize
La directive @synthesize sutilise dans la dnition dune classe (chier .m) pour gnrer le code de laccesseur et du manipulateur dune proprit.
@synthesize labelDollar;

Cette instruction gnre le code permettant daccder la proprit labelDollar.

2.4. Manipulation des objets en Objective-C

69

Notation pointe
La notation pointe permet dallger la lecture du code source.
[objet propriete] et [objet setPropriete:newValue] sont remplacs par objet.proprit.
NSString *textDollar = labelDollar.text; labelEuro.text = textEuro;

quivaut
NSString *textDollar = [labelDollar text]; [labelEuro setText:textEuro];

Cration
La cration dune instance seffectue en deux tapes :
j j

allocation de la mmoire ; initialisation des variables dinstance.

Lallocation de mmoire est effectue par lenvoi du message +alloc (dnie dans la classe NSObject, mre de toutes les classes) la classe de linstance crer. Ce message renvoie un pointeur sur linstance qui vient dtre alloue. Par exemple, pour allouer une nouvelle chane de caractres :
// dclaration dun pointeur sur UITextField UITextField *monTextField; monTextField = [UITextField alloc];

chec lors de lallocation


Si la cration de lobjet choue (par exemple sil ny a plus de mmoire disponible), le message retourne la constante nil.

nil nil est la constante de type id qui signie pointeur nul. nil est quivalent NULL la seule diffrence quil est de type pointeur sur un objet alors que NULL est un pointeur gnrique.

On doit toujours initialiser une instance avant de lutiliser, cest--dire dnir les valeurs de ses variables dinstance. Les mthodes dinstance dont le nom commence par init servent initialiser les variables dinstance.

70

2. Interactions simples

Initialiseur
Un initialiseur est une mthode dinstance destine initialiser les variables de linstance sur laquelle elle est appele. Une classe peut comporter plusieurs initialiseurs, leur nom commence toujours par init. Linitialiseur renvoie un pointeur sur linstance initialise. Chaque classe doit avoir un initialiseur dsign unique, gnralement celui qui offre le plus de paramtres. Tous les autres initialiseurs appellent linitialiseur dsign qui est le seul effectuer rellement le travail. Tout initialiseur dsign doit commencer par appeler linitialiseur dsign de sa superclasse.

Retour de init
Si linitialisation ne se droule pas correctement, par exemple dans le cas o les paramtres passs ne sont pas corrects, linitialiseur dsign doit librer la mmoire alloue et retourner nil.

Le message +alloc renvoie un pointeur sur une instance, et le message init est susceptible de modier ce pointeur, cest pourquoi il est dusage de grouper lallocation et linitialisation dans une seule instruction.
UITextField *monTextField; monTextField = [[UITextField alloc] initWithFrame:rect];

On peut mme combiner la dclaration, lallocation et linitialisation en une seule instruction.


UITextField *monTextField = [[UITextField alloc] initWithFrame:rect];

message nil
Que se passe-t-il si lallocation renvoie nil puis que lon envoie un message dinitialisation au pointeur nul ? Rien. Le langage Objective-C autorise lenvoi de messages nil.

Un initialiseur doit appeler linitialiseur dsign de sa superclasse. Le schma habituel pour dnir un initialiseur est le suivant :
- (id)init { if (self = [super init]) { // initialisation des variables dinstances } return self;

2.4. Manipulation des objets en Objective-C

71

Cest loccasion de faire la connaissance de deux mots-cls importants en Objective-C : super et self.

super super est un mot-cl Objective-C qui dsigne la superclasse de linstance


courante. On lutilise dans une mthode dinstance pour appeler une mthode de sa superclasse. Par exemple, le message [super init] dans un initialiseur appelle linitialiseur de la superclasse ; avant dinitialiser les variables dinstance dnies dans une classe, on initialise les variables dnies dans la superclasse.

self self est un mot-cl Objective-C qui dsigne linstance courante. On lutilise par exemple dans une mthode dinstance pour envoyer un autre message cette mme instance.

Libration
Lorsquun objet doit tre dtruit, il reoit un message dealloc. La mthode dinstance dealloc ne retourne pas de valeur. Avant dtre dtruit, une instance doit penser dtruire, ou du moins librer (nous verrons bientt la subtile diffrence) les instances quelle possde. En dautres termes, les variables dinstances qui occupent de la mmoire doivent tre libres dans la mthode dinstance dealloc ; il sagit des variables de type pointeur, en particulier les pointeurs sur des objets. Pour librer un objet, il suffit de lui envoyer le message release.
[textDollar release];

Le langage Objective-C 2.0 sous MacOSX dispose dun ramassemiettes (garbage collector), comme le langage Java, qui rend inutiles les instructions de libration (release). Cette caractristique nest actuellement pas disponible sous iPhone OS en raison du manque de mmoire (il faut la librer ds que possible) et du manque de performance du processeur (le ramasse-miettes est gourmand en processeur). Les initialiseurs commencent par initialiser les variables dinstances de la superclasse ; linverse, la mthode dealloc doit se terminer

72

2. Interactions simples

par un appel la mme mthode sur la superclasse. La structure classique dune mthode dealloc est la suivante :
- (void)dealloc { // libration des variables dinstances [super dealloc]; }

Release et pas dealloc


Pour librer une instance, on lui transmet le message release. On ne doit jamais transmettre directement un message dealloc un objet. Le message release informe linstance que lun des objets qui lutilisent nen a plus besoin. Le message dealloc sera transmis automatiquement cette instance lorsquelle ne sera plus employe par aucun objet.

2.5. Check-list
Ce chapitre a commenc par une introduction la Programmation
Oriente Objet, ce qui nous a permis de dcouvrir :
j j j j

les objets, classes et instances ; ltat des objets, leur comportement et la transmission de messages ; le principe dencapsulation ; lhritage.

Nous avons ralis notre premire application interactive Convertisseur1 pour notre prochain voyage aux tats-Unis. Nous avons fait connaissance avec :
j j j j j

les outlets, les actions et le mcanisme cible-action ; le champ de texte UITextField ; larbre dhritage de UITextField ; la hirarchie des vues ; la saisie de code source sous XCode et la terminaison de code.

Nous avons termin par un approfondissement de la syntaxe du langage Objective-C :


j j

clause #import ; dclaration dune classe :


@interface ;

dclaration des variables dinstance ;


@property pour dclarer les proprits ;

2.5. Check-list

73

dclaration des mthodes de classe et dinstance.


j

dnition dune classe :


@implementation ; @synthesize pour gnrer laccesseur et le manipulateur dune proprit.

j j j

envoi de message ; mots-cls super et self et nil ; mthodes impliques dans le cycle de vie des objets :
+alloc ;

initialiseurs init et initialiseur dsign ;


release ; dealloc.

Lapplication Convertisseur1 est bourre de dfauts. Nous allons corriger cela ds le prochain chapitre. Ce sera loccasion de dcouvrir de nouveaux mcanismes de Cocoa Touch.

74

2. Interactions simples

GESTION DE LA MMOIRE
Diagnostiquer les fuites mmoire avec Leaks ................................................ 77 viter les fuites mmoire ......................................................................................... 84 Amliorer Convertisseur1 ........................................................................................ 90 Check-list ......................................................................................................................... 98

75

CHAPITRE 3

Alors quun ordinateur dispose frquemment de 1 Go de RAM ou plus, la mmoire est limite 128 Mo sur un iPhone. Cet espace est partag entre le systme iPhone OS, laffichage graphique et lapplication en cours dexcution ; cette dernire ne dispose que denviron 64 Mo. La mmoire est donc une ressource prcieuse quil faudra conomiser. Nous allons comprendre dans ce chapitre comment est gre la mmoire sous Cocoa Touch et Objective-C. Nous mettrons en uvre les Instruments du SDK pour chasser les erreurs courantes relatives la gestion de la mmoire et nous amliorerons le comportement de notre application Convertisseur1 vis--vis de la mmoire.

3.1. Diagnostiquer les fuites mmoire avec Leaks


Zombi
Vous connaissez certainement les morts-vivants de cinma et autres zombis de mme nature. Un zombi Objective-C est aussi un objet mort-vivant. la cration dune instance, il faut conserver son adresse dans une variable de type pointeur sur un objet. Cette variable est appele rfrence sur linstance. Pour pouvoir mettre un message vers un objet, vous devez disposer dune rfrence sur cet objet. Dans lexemple, les messages sont transmis linstance rfrence par la variable textEuro.
// cration dune instance NSString *textEuro = [NSString alloc]; // mission dun message textEuro = [textEuro initWithFormat: @"%.2f",euro]; // mission dun autre message valeur = [texteuro floatValue];

Si nous perdons la rfrence un objet, nous ne pouvons plus lui envoyer de message. Dans le deuxime exemple, nous crons une instance (appelons-la Objet1) rfrence par le pointeur textEuro puis une seconde instance (Objet2) rfrence par le mme pointeur ; la valeur prcdente de textEuro est alors perdue.
// cration dune instance Objet1 NSString *textEuro = [NSString alloc]; // mission dun message vers Objet1 rfrenc par textEuro textEuro = [textEuro initWithFormat: @"%.2f",euro]; // cration dune instance Objet2
3.1. Diagnostiquer les fuites mmoire avec Leaks

77

textEuro = [NSString alloc]; // mission dun message vers Objet2, // Objet1 nest plus accessible textEuro = [textEuro initWithFormat: @"%.2f",euro];

Nous navons plus de rfrence vers Objet1. Cette instance nest pas dtruite (elle est toujours vivante) mais nest plus accessible (comme si elle tait morte) ; Objet1 est un zombi.

Zombi
Un zombi est un objet qui nest pas accessible car il nest rfrenc par aucun pointeur dans lapplication. Cet objet est inutilisable ; il occupe donc inutilement de la mmoire.

Si vous avez dj vu des zombis au cinma, vous savez quils ne sont pas trs sympathiques. Et les zombis Objective-C, gentils ou mchants ? Vous lavez dj devin ; ils ne sont pas trs sympathiques non plus, pas vraiment dangereux, mais nuisibles car ils occupent un espace mmoire qui est irrmdiablement perdu ; cet espace sera rcupr par le systme uniquement lorsque lutilisateur quittera lapplication.

Dtecter les fuites mmoire


Dnition dune fuite mmoire
Un zombi apparat cause dune erreur de programmation (perte de la dernire rfrence dun objet non libr). Lorsque ces erreurs sont trop nombreuses ou lorsquelles sont rencontres plusieurs fois au cours de lexcution, le nombre de zombis saccrot au fur et mesure ; cest ce que lon nomme une fuite mmoire. Cette erreur trs courante peut dgrader les performances de lapplication, voire provoquer un plantage.

Fuite mmoire
Erreur courante en programmation oriente objet. Une fuite mmoire est laccroissement progressif, tout au long de lexcution dune application, de la mmoire alloue inutilement. Ce phnomne peut aboutir une diminution des performances ou un plantage de lapplication.

Nous allons provoquer une fuite mmoire dans notre application Convertisseur1. Modiez le code source de Convertisseur1ViewController.m ; mettez en commentaire linstruction qui libre texteEuro.
78
3. Gestion de la mmoire

- (IBAction) changeValue { NSString *textDollar = labelDollar.text; float dollar = [textDollar floatValue]; float euro = dollar / 1.4908; NSString *textEuro = [[NSString alloc] initWithFormat: @"%.2f",euro]; labelEuro.text = textEuro; // [textEuro release]; }

chaque excution de la mthode changeValue, cest--dire chaque modication du champ de texte contenant la valeur en dollars, une nouvelle instance de NSString est rfrence par textEuro ; linstance prcdente devient un zombi.

Figure 3.1 : Cration dune fuite mmoire

Instruments Leaks
Il est indispensable dinstrumenter lapplication en cours dexcution pour dtecter les fuites mmoire (leaks). Nous allons mettre en uvre les instruments fournis avec le SDK dApple sur notre application Convertisseur1 modie. 1 Reconstruisez lapplication mais ne lancez pas son excution immdiatement ; commande Build du menu Build sous XCode ou X+[B]. 2 Lancez lexcution sous instrumentation des fuites mmoire. Pour cela, slectionnez la commande Leaks du sous-menu Start with Performance Tools du menu Run sous XCode.

3.1. Diagnostiquer les fuites mmoire avec Leaks

79

Figure 3.2 : Lancement du dtecteur de fuites mmoire

Lapplication Convertisseur1 se lance dans le simulateur iPhone en mme temps que lapplication Instruments ; lenregistrement des vnements mmoire dbute automatiquement. 3 Manipulez lapplication avec le simulateur ; saisissez des chiffres dans le champ de texte contenant le montant en dollars, effacez des caractres puis recommencez pendant une trentaine de secondes. 4 Quittez lapplication Convertisseur1 en pressant le bouton Home du simulateur ou laide de la slection de touches z+X+[H]. Lenregistrement des donnes sous Instruments sarrte automatiquement. Dans la fentre principale de lapplication Instruments, ralisez les oprations suivantes : 1 Slectionnez loutil Leaks dans la liste des instruments sur la partie gauche, en haut de la fentre. 2 Cliquez sur licne Extended Detailed View (Vue dtaille tendue) sur la barre dtat en bas de la fentre.

3 Dans la partie centrale de la fentre, chaque ligne est un zombi. Slectionnez une de ces lignes ; ltat de la pile (stack trace) au

80

3. Gestion de la mmoire

moment de la dernire opration mmoire sur cet objet apparat dans la partie droite de la fentre (vue dtaille tendue).

Figure 3.3 : Instrument dtecteur de zombis (leaks)

Il nest pas inhabituel que la pile contienne une cinquantaine dlments. Chaque lment est dcrit sur deux lignes :
j j

le nom de la fonction appele ; le nom du framework ou du projet XCode et du chier source auquel appartient cette fonction.

Pile
La Pile (Stack) est lespace mmoire utilis par le processeur pour conserver le contexte (paramtres et variables locales) dune fonction ou dune mthode. Ltat de la pile permet de connatre lenchanement des appels de fonction un instant donn ainsi que les valeurs des paramtres et des variables locales de chaque fonction lors de lappel la suivante. La pile informatique fonctionne comme une pile dassiettes. Lors de lappel une fonction, une assiette est ajoute en haut de la pile pour contenir le contexte de la fonction appele. Lorsquune fonction se termine (instruction return), lassiette en haut de la pile est enleve ; le contexte de la fonction qui se termine est dtruit et lon revient au contexte de la fonction appelante.

3.1. Diagnostiquer les fuites mmoire avec Leaks

81

Sil y a des erreurs de programmation, elles sont probablement davantage dans le code que nous avons crit que dans les frameworks du SDK. Recherchons dans la vue dtaille tendue (partie droite de la fentre dInstruments) les fonctions appartenant au projet Convertisseur1. Nous en trouvons trois :
j

Tout en haut de la liste ; les fonctions start et main. Ce nest pas tonnant, toutes les applications commencent par lexcution de ces deux fonctions. Vers le bas de la liste, nous trouvons le message [Convertisseur1
ViewController changeValue].

Lapplication Instruments dtecte les fuites mmoire que nous avons cres.

Diagnostiquer les fuites mmoire


Une fois identies la fonction ou la mthode en cause, il faut dterminer quel est prcisment lobjet qui se transforme en zombi. 1 Double-cliquez sur le message [Convertisseur1ViewController changeValue] dans la vue dtaille tendue sous Instruments. Ce double-clic vous renvoie vers le code source de la mthode en cause, sous XCode ; une ligne de code est surligne.

Figure 3.4 : Identication du zombi

Linstruction de notre application qui provoque une fuite mmoire est celle qui cre une instance de NSString rfrence par la variable textEuro. Cest cette instance quil faut librer pour viter les zombis.

82

3. Gestion de la mmoire

2 Enlevez la mise en commentaire de linstruction [textEuro release];, reconstruisez lapplication et testez-la nouveau en utilisant linstrument Leaks. Il y a beaucoup moins de fuites mmoire.

Figure 3.5 : Vrication de la diminution des fuites mmoires

Selon la version du SDK que vous utilisez, il est mme possible quil ny ait plus du tout de fuites mmoire. Il est aussi possible quil reste quelques lignes, vriez que le code que vous avez crit nest pas impliqu dans ces lignes rsiduelles. Nous venons dillustrer la recherche des fuites mmoire en utilisant une application dans laquelle nous avons introduit une erreur de programmation. Bien sr, la recherche de ce type derreur est un peu moins facile dans la ralit mais le principe est toujours le mme : mettre en uvre linstrument Leaks. La premire chose faire est tout de mme dviter dintroduire ce genre derreur dans notre code source. Cest pourquoi nous allons tudier les rgles qui rgissent la gestion de la mmoire.

Chassez les fuites mmoire


Malgr tout le soin que nous mettrons respecter les rgles de gestion de la mmoire, il est indispensable de vrier que notre programmation est correcte en testant notre application laide de linstrument Leaks.

3.1. Diagnostiquer les fuites mmoire avec Leaks

83

3.2. viter les fuites mmoire


Compteur de rfrences
Chaque instance dispose dun compteur de rfrences qui lui est propre, quelle que soit sa classe dappartenance. Lorsquune instance est cre, son compteur de rfrences (retain count) prend la valeur 1. Lorsquune instance reoit le message retain, son compteur de rfrences est incrment, tandis que lorsquelle reoit le message release, il est dcrment. Le message retainCount permet de connatre la valeur du compteur de rfrences. Lorsque son compteur de rfrences atteint la valeur nulle, le message dealloc est transmis linstance :
// cration le compteur vaut 1 MaClasse *monInstance = [[MaClasse alloc] init]; // le compteur est incrment, il vaut 2 [monInstance retain]; // compteur vaut 2 int compteur = [monInstance retainCount]; // le compteur est dcrment, il vaut 1 [monInstance release]; // le compteur est dcrment 0, linstance est dtruite [monInstance release];

Compteur de rfrences
Chaque objet dispose dun compteur de rfrences (retain count) qui vaut 1 la cration de linstance. Ce compteur est incrment par le message retain, il est dcrment par le message release. Lobjet est dtruit lorsque son compteur de rfrence est gal 0.

Rappelez-vous, pour chacune des classes que vous crivez, il est important de dnir une mthode dealloc dans laquelle vous transmettez un message release chaque instance retenue par la lobjet de la classe (en particulier les proprits). Il faut invoquer dealloc sur la superclasse.

Gestion des proprits


Logiquement, sil faut librer les proprits dune instance lorsquelle est dtruite, cest quelles ont t retenues auparavant.

84

3. Gestion de la mmoire

Attributs des proprits


Souvenez-vous du chier Convertisseur1ViewController.h :
#import <UIKit/UIKit.h> @interface Convertisseur1ViewController : UIViewController { IBOutlet UITextField *labelDollar; IBOutlet UITextField *labelEuro; } @property (retain,nonatomic) UITextField *labelDollar; @property (retain,nonatomic) UITextField *labelEuro; - (IBAction) changeValue; @end

Nous avons ajout deux attributs la clause @property : retain et nonatomic. Lattribut retain indique que le manipulateur de la proprit doit la retenir et quil doit librer la valeur prcdente. Le principe du code du manipulateur gnr par la clause @synthesize est alors le suivant :
- (void) setLabelDollar: (UITextField *) textField { [textField retain]; [labelDollar release]; labelDollar = textField; }

Le tableau rsume les attributs utilisables avec la clause @property.


Tableau 3.1 : Principaux attributs de la clause @property Thme Nom des mthodes gnres Attribut Rle Permet de dnir un nom pour laccesseur autre que celui par dfaut.

getter=
nom-de-l-accesseur

setter= Permet de dnir un nom pour le nom-du-manipulateur manipulateur autre que celui par dfaut.
Proprit modiable

readwrite
(attribut par dfaut)

@synthesize gnrera laccesseur et le manipulateur. @synthesize gnrera seulement laccesseur.


Dans le manipulateur gnr par @synthesize, la nouvelle valeur remplace simplement lancienne valeur. Dans le manipulateur gnr par @synthesize, la nouvelle valeur est retenue et lancienne valeur est libre. Dans le manipulateur gnr par @synthesize, la nouvelle valeur est duplique et lancienne valeur est libre.

readonly
Gestion de la mmoire Le com- assign pilateur met un avertissement si lun de ces attributs nest pas utilis

retain

copy

3.2. viter les fuites mmoire

85

Tableau 3.1 : Principaux attributs de la clause @property Thme Atomicit Attribut Rle Permet damliorer les performances dans une application nutilisant pas le paralllisme dexcution (multi-threading).

nonatomic

Recommandations demploi
nonatomic
Sur iPhone OS, il est recommand demployer lattribut nonatomic, sauf dans les cas rares o les instances de la classe sont susceptibles dtre utilises dans un contexte dexcution concourante. Nous ntudierons pas ces situations dans le cadre de cet ouvrage.

retain
Lattribut retain est recommand pour les proprits qui sont des instances de classe Objective-C. Il nest pas utilisable pour les proprits de type scalaire.

Figure 3.6 : Relation dappartenance

Dans cet exemple, lobjet A possde lobjet B. La proprit B doit tre retenue (dclare avec lattribut retain). Les proprits retenues doivent tre libres dans la mthode dealloc. Un objet B peut appartenir simultanment plusieurs autres objets. Si chacun des propritaires retient cet objet B, son compteur de rfrences sera gal au nombre de propritaires. Cela garantit que lobjet B sera dtruit seulement lorsquil naura plus de propritaires.

86

3. Gestion de la mmoire

assign
Lattribut assign est employ avec des proprits de type scalaire (par opposition Objet), cest--dire les types fondamentaux du langage C (int, float, double, char, struct, etc.) ou leur quivalent Cocoa Touch (NSInteger, CGRect, etc.). On lutilise galement avec des proprits de type Objet lorsque lon souhaite quun objet connaisse un autre objet sans pour autant le possder. Dans lexemple, lobjet A possde lobjet B, et donc la proprit B de lobjet A est dclare avec lattribut retain. Il est alors incorrect que lobjet B possde lobjet A. Par analogie, vous possdez votre iPhone mais lui ne vous possde pas. Il vous connat nanmoins car vous avez saisi votre nom lorsque vous lavez initialis ; la proprit A de lobjet B est dclare avec lattribut assign.

Figure 3.7 : Connaissance (Assign) nest pas possession (retain)

copy
Lattribut copy indique que le paramtre pass au manipulateur doit tre dupliqu avant dtre affect la proprit.
-(void)setString:(NSString *)newString { if (string != newString) { [string release]; string = [newString copy]; } }

La mthode copy est dclare dans NSObject. Elle doit tre dnie dans toutes les classes o lon souhaite en disposer. Elle duplique linstance (et toutes ses proprits) et renvoie un pointeur sur le duplicata.

3.2. viter les fuites mmoire

87

Responsabilits des objets


Rgle de gestion de la mmoire
La rgle qui permet dviter les zombis est simple.

Rgle de gestion de la mmoire


Une classe dobjet qui obtient une instance par +alloc, par copy (ou ses drivs) ou qui retient une instance (retain) est responsable de sa libration. Les instances obtenues par un autre moyen ne doivent pas tre libres.

Dire quune classe est responsable de la libration des instances obtenues, cela signie que le programmeur doit veiller envoyer le message release aux variables rfrenant un objet avant de les modier ; cest ce que nous avons fait dans la mthode changeValue de la classe Convertisseur1ViewController. Quels sont les autres moyens dobtenir une instance ? Il sagit de faon gnrale de la valeur de retour dune mthode autre que +alloc ou copy. Vous voyez un exemple ? Un accesseur bien sr, renvoie une rfrence sur un objet sans lintention den transfrer la proprit ; il appartient celui qui le reoit de le retenir sil le souhaite.

Cycle de vie des objets


La dure de vie des objets pendant lexcution dune application est trs variable. Certains objets sont crs au lancement de lapplication et vont perdurer jusqu sa terminaison, par exemple les champs de texte de notre Application Convertisseur1. Dautres ont une vie extrmement brve : linstance textEuro de la mthode changeValue. Dans le contexte de liPhone OS o la mmoire est une denre prcieuse, il est recommand de dtruire les objets ds que possible. Mais que se passe-t-il dans le cas o nous voulons crire une mthode qui cre un objet pour le retourner. Par exemple, nous voulons ajouter la classe Convertisseur1ViewController une mthode qui retourne une chane de caractres contenant la valeur convertie en euros.
- (NSString *) euroAsString { NSString *textDollar = labelDollar.text; float dollar = [textDollar floatValue]; float euro = dollar / 1.4908; NSString *textEuro = [[NSString alloc] initWithFormat: @"%.2f",euro];

88

3. Gestion de la mmoire

return textEuro; }

Le problme ici est que nous violons la rgle de gestion de la mmoire : la mthode obtient une instance par +alloc mais ne se proccupe pas de sa libration ; si la mthode librait cette instance, elle ne pourrait pas la retourner lappelant. Heureusement, il existe une autre faon de librer les objets qui va nous permettre de continuer respecter la rgle.

Pool dautolibration
Il faut ajouter une toute petite instruction importante, avant de retourner linstance nouvellement cre :
- (NSString *) euroAsString { NSString *textDollar = labelDollar.text; float dollar = [textDollar floatValue]; float euro = dollar / 1.4908; NSString *textEuro = [[NSString alloc] initWithFormat: @"%.2f",euro]; [textEuro autorelease]; return textEuro; }

Le message autorelease programme la libration pour plus tard. Ainsi la mthode euroAsString soccupe de librer linstance cre ; elle respecte donc la rgle mais le fait de faon se laisser le temps de renvoyer la valeur attendue. Et quand la libration sera-t-elle opre ? En fait, les objets auxquels ont transmet le message autorelease sont ajout au pool dautolibration (autorelease pool) courant. Lorsque le pool est dtruit, tous les objets qui y sont rattachs sont librs. Sous Cocoa Touch, un pool dautolibration est cr au dbut de chaque boucle dvnement et dtruit la n de la boucle.

Boucle dvnement
Une application sur iPhone passe son temps attendre des vnements et y rpondre. Lorsque lutilisateur saisit des caractres sur le clavier ou lorsquil touche un bouton, lorsque un appel est reu, que lappareil est secou, etc. Tous ces vnements sont reprsents par des instances de la classe UIEvent par le systme iPhone OS puis transmis lapplication.

3.2. viter les fuites mmoire

89

Lorsque lapplication reoit un vnement, elle dbute une boucle dvnement :


j j

cration dun pool dautolibration ; dtermination du contrle (instance de la classe UIControl) dans lapplication qui peut traiter lvnement (par exemple un champ de texte dans le cas de saisie de caractres) ; traitement par le contrle dune partie de lvnement (affichage du caractre) et gnration de laction ventuellement attache suivie dune transmission la cible ; traitement par la cible de laction (changeValue dans notre application) ; n de traitement de lvnement par lapplication (mise jour de laffichage des autres vues) ; destruction du pool dautolibration ; attente de lvnement suivant.

j j

3.3. Amliorer Convertisseur1


Nous allons vrier que notre application respecte la rgle de gestion de la mmoire. La seule classe que nous avons modie est Convertisseur1 ViewController ; nous allons donc y concentrer nos efforts.

Instances manipules
Commenons par identier la liste des instances obtenues. Nous allons dresser un tableau pour prciser comment nous obtenons chaque instance et comment nous la librons.
Tableau 3.2 : Liste des instances manipules dans Convertisseur1ViewControlleur Porte Proprit Instance Obtention manipulateur Libration

labelDollar retain dans le labelEuro retain dans le manipulateur


accesseur de text Inutile car obtenu autrement que sur labelDollar par +alloc, retain ou

changeValue textDollar

copy

textEuro

+alloc

release

90

3. Gestion de la mmoire

Nous nous apercevons que nous ne grons pas correctement les proprits. Il faut y remdier.

Mise en conformit avec la rgle


Mthode -dealloc
Nous avons oubli de librer les proprits dans la mthode dealloc de la classe. Slectionnez le chier Convertisseur1ViewController.m sous XCode. La mthode dealloc a dj t prpare par XCode ; modiez cette mthode pour librer les proprits.
- (void)dealloc { self.labelDollar = nil; self.labelEuro = nil; [super dealloc]; }

Libration des proprits


Notez la faon dont nous librons les proprits, au lieu dcrire [labelDollar release];, nous utilisons la notation pointe qui est quivalente [self setLabelDollar:nil];. La proprit tant dclare avec lattribut retain, le manipulateur commence par librer la proprit Actuelle ; cest ce que nous souhaitons. Lintrt demployer self.labelDollar = nil est double :

1 la proprit vaut nil au lieu de contenir une rfrence obsolte, ce qui va


viter beaucoup de plantage ;

2 cette instruction fonctionne aussi bien quel que soit lattribut (assign, retain, copy) de la proprit, ce qui nest pas le cas du message release qui est une erreur de programmation si lattribut est assign.
Ainsi le code de notre mthode dealloc est insensible aux modications dattribut que nous pourrions faire par la suite. Notre code est plus robuste ; il est plus facile den assurer la maintenance.

Mthode -viewDidUnload
XCode a prpar dautres mthodes dans la classe Convertisseur1
ViewController.

3.3. Amliorer Convertisseur1

91

Figure 3.8 : XCode a prpar des mthodes

Nous pouvons voir juste au-dessus de la mthode dealloc une mthode viewDidUnload dans laquelle nous pouvons lire un commentaire nous incitant y librer les outlets ; cest exactement ce que nous venons de faire dans la mthode dealloc. La mthode viewDidUnLoad est appele lorsque la Vue contrle par linstance du contrleur de Vue vient dtre libre. Cela se produit quand la mmoire sature et que la Vue nest pas affiche lcran ; elle occupe inutilement de lespace mmoire et pourra tre recharge partir du chier NIB si lutilisateur y revient. Cette caractristique est utile uniquement dans les applications multivues, o lutilisateur peut passer dune vue lautre ; les vues qui sortent de laffichage un moment donn restent dans la mmoire an de pouvoir tre raffiches plus rapidement. Notre application Convertisseur1 nest pas multivue, pour linstant, mais prenons tout de suite de bonnes habitudes. Modiez le code de la mthode viewDidUnload :
- (void)viewDidUnload { // Release any retained subviews of the main view. // e.g. self.myOutlet = nil; self.labelDollar = nil; self.labelEuro = nil; }

Factorisation du code
Les mthodes dealloc et viewDidUnload se ressemblent beaucoup.

92

3. Gestion de la mmoire

Cest une bonne pratique de la programmation que dviter de telles ressemblances ; elles rendent le code plus difficile maintenir. Llimination de ces ressemblances sappelle la factorisation du code.

Factorisation du code
La factorisation de code est llimination des squences de code qui se ressemblent. De telles ressemblances rendent le code difficile maintenir et sont sources derreurs.

Dans le cas prsent, le code est facile factoriser. Le rle de viewDidUnload est de librer les outlets, et nous voulons que les outlets soient librs lors de lappel de dealloc : il suffit dappeler viewDidUnload depuis dealloc. Modiez le code de la classe Convertisseur1ViewController.
- (void)viewDidUnload { // Release any retained subviews of the main view. // e.g. self.myOutlet = nil; self.labelDollar = nil; self.labelEuro = nil; } - (void)dealloc { [self viewDidUnload]; [super dealloc]; }

// libre les outlets

Nous avons fait un excellent travail. Reconstruisez lapplication et testez-la. Jetez un coup dil avec linstrument Leaks pour vrier que tout fonctionne, sans fuite mmoire provoque par votre code.

Rsum
Rsumons les recommandations importantes qui vous serviront pour tous les dveloppements :
j

Souvenez-vous de la rgle de gestion de la mmoire : une classe propritaire dun objet est responsable de sa libration. laborez un tableau des instances manipules pour chaque classe que vous dveloppez, cela vous aidera vrier que la rgle est respecte. Factorisez votre code, il y aura moins derreurs. Utilisez linstrument Leaks pour vrier quil ny a pas de fuites mmoire.

j j

3.3. Amliorer Convertisseur1

93

Rfrences obsoltes
Ce chapitre a trait jusquici des zombis, des fuites mmoire, donc des risques lis au manque de libration. Nous ne pouvons le clore sans dire ce qui se passe si on libre trop. Que se passe-t-il si une instance reoit trop de message release ? Autrement dit, que se passe-t-il si lon envoie un message un objet qui a t dtruit (on parle de rfrence obsolte) ? Essayons.

Rfrence obsolte
Une rfrence obsolte est une variable qui pointe sur une instance qui nexiste plus.

Provoquer une rfrence obsolte


Modiez la mthode changeValue ; librez linstance textEuro avant de laffecter au champ de texte contenant le montant en euros.
- (IBAction) changeValue { NSString *textDollar = labelDollar.text; float dollar = [textDollar floatValue]; float euro = dollar / 1.4908; NSString *textEuro = [[NSString alloc] initWithFormat: @"%.2f",euro]; [textEuro release]; labelEuro.text = textEuro; // [textEuro release]; }

Construisez lapplication et testez-la. Inutile ici demployer les instruments. Lapplication plante et on revient XCode ds que lon essaie de saisir un caractre dans le champ de texte contenant le montant en dollars. Ce plantage peut se manifester de diffrentes faons : laffichage peut simplement se ger ou un message derreur peut tre mis ou lapplication quitte brutalement sans message, ou encore il ne se passe plus rien (voir Figure 3.9). Si un message est affich dans une bote de dialogue, vous pouvez cliquer sur le bouton Rapport pour avoir plus de dtails sur lerreur (inutile denvoyer le rapport Apple) (voir Figure 3.10).

94

3. Gestion de la mmoire

Figure 3.9 : Diffrentes faons de planter

Figure 3.10 : Rapport dtaill dune rfrence obsolte

Ce rapport indique quun accs mmoire illgal a t effectu : EXC_BAD_ACCESS.

3.3. Amliorer Convertisseur1

95

Diagnostiquer lerreur
Dans tous les cas, que le message saffiche ou pas, nous pouvons diagnostiquer lerreur en utilisant le Debogueur de XCode (debugger). Slectionnez la commande Debug - Breakpoints On du menu Run de XCode ou utilisez la combinaison de touches z+X+[Y]. Testez votre application jusquau plantage. Si la fentre du dbogueur ne saffiche pas sous XCode, slectionnez la commande Debugger du menu Run (z+X+[Y]). Une fois affiche, elle nous permet de visualiser ltat dtaill du programme au moment du plantage. Slectionnez la ligne numro 2 dans la partie gauche de la fentre pour voir ce qui sest pass dans notre mthode changeValue.

Figure 3.11 : tat du programme lors du plantage

Le programme sest arrt alors quil essayait daffecter linstance textEuro au champ de texte devant afficher la valeur en euros (partie basse de la fentre). Nous voyons aussi et surtout, sur la partie droite de la fentre, que la variable textEuro prsente une valeur invalide (out of scope). Cette variable pointe sur une instance qui nexiste pas puisquelle vient dtre dtruite dans la ligne de code prcdente.

96

3. Gestion de la mmoire

Si la barre dtat ne contient pas de message derreur, cliquez sur le bouton Continue de la barre doutils. Vous pouvez alors lire le message "GDB: Program received signal: EXC_BAD_ACCESS" dans la ligne dtat en bas de la fentre. Nous venons de montrer que lutilisation dune rfrence obsolte provoquait gnralement le plantage de lapplication associ lmission dun signal EXC_BAD_ACCESS. Nous avons vu galement comment utiliser le dbogueur pour localiser linstruction ayant provoqu ce plantage et visualiser ltat des variables ce moment-l.

La fentre du dbogueur
Nous allons terminer par quelques explications concernant la fentre du dbogueur qui est compose de quatre parties :
j

une barre doutils en haut, que nous apprendrons bientt utiliser ; ltat de la pile dans la partie gauche : les fonctions de notre application y apparaissent en couleur fonce, signe que nous pouvons en visualiser le code source ; le code source dans la partie basse ; lorsque nous slectionnons une fonction de notre application dans ltat de la pile, ou le code machine lorsque nous slectionnons une fonction de lun des frameworks de Cocoa Touch ; ltat des variables de la fonction slectionne dans la partie droite. L aussi, cet tat est facile interprter uniquement si nous slectionnons une fonction crite dans notre application ; une barre dtat en bas de la fentre.

Le code source et ltat des variables sont lisibles dans le dbogueur uniquement pour les fonctions qui sont compiles en mode Debug. Ce mode de compilation indique que le code excutable doit tre enrichi pour permettre au dbogueur dafficher ces informations. Lorsque vous livrerez votre application sur lAppStore, vous pourrez les supprimer et compiler pour cela en mode Release. Pour changer le mode de compilation, utilisez le sous-menu Set Active Build Conguration du menu Project sous XCode (voir Figure 3.12). Vous pouvez aussi utiliser le menu Overview de la barre doutils de XCode.

3.3. Amliorer Convertisseur1

97

Figure 3.12 : Changement du mode de compilation sous XCode

3.4. Check-list
Nous avons vu dans ce chapitre comment grer la mmoire, ressource prcieuse dans le contexte de liPhone : la rgle de gestion de la mmoire ainsi quune mthode pour sassurer que la rgle est applique dans chacune de nos classes. Nous avons galement examin les 2 erreurs les plus courantes et la faon de les liminer :
j

les fuites mmoire et la chasse aux zombis avec linstrument Leaks ; les rfrences obsoltes et leur localisation avec le Dbogueur.

Ce parcours a t loccasion dapprofondir quelques lments de la programmation sur iPhone :


j j j j

le compteur de rfrences et les messages retain et release ; les attributs de la clause @property ; le pool dautolibration et le message autorelease ; le traitement des demandes de libration mmoire dans les contrleurs de vues dans la mthode viewDidUnload ; le fonctionnement de la boucle dvnement ; le principe de factorisation du code.

j j

98

3. Gestion de la mmoire

MOTIFS FONDAMENTAUX
Mcanisme de dlgation ..................................................................................... 101 Amliorer Convertisseur1 ..................................................................................... 115 Motif MVC ..................................................................................................................... 133 Challenges .................................................................................................................... 134 Check-list ....................................................................................................................... 140

99

CHAPITRE 4

Nous allons faire connaissance avec quelques motifs de conception(design patterns) fondamentaux de la programmation sur iPhone : la dlgation, le motif Modle-Vue-Contrleur (MVC, Model-ViewController), le codage par valeur de cl (KVC et Key Value Coding). Ces mcanismes permettront damliorer notre convertisseur de monnaies et daboutir une application de niveau professionnel. Prenons en compte les lments suivants :
j j j

Nous voulons interdire la frappe de lettres. Nous souhaitons pouvoir faire disparatre le clavier. Nous allons vraisemblablement trouver dautres amliorations.

4.1. Mcanisme de dlgation


Dlgu
Commenons par interdire lutilisateur de frapper des lettres. Nous voulons modier le comportement de lobjet UITextField vis-vis de lutilisateur. La manire la plus directe dy parvenir serait de modier lobjet lui-mme, ou de crer un autre objet nomm UINumericField par exemple qui hrite de UITextField. Il faudrait ensuite rcrire quelques mthodes drives de celles de UITextField pour donner UINumericField le comportement souhait. Tout cela parat compliqu. La drivation de classe est en effet une opration dlicate qui ncessite une trs bonne comprhension du fonctionnement de la classe mre. La dlgation permet de modier le comportement dun objet sans avoir le modier ni le driver. Les objets UITextField disposent dun outlet delegate (objet dlgu) congurable sous Interface Builder (voir Figure 4.1). Lobjet dlgu reoit un message avant ou aprs chaque opration effectue par son propritaire :
j

pour demander lautorisation au dlgu deffectuer cette opration ; pour linformer et lui permettre de complter lopration.

De faon gnrale, une information est transmise par un message dont la mthode est fonction de lopration, qui ne retourne pas de valeur et prend comme unique paramtre une rfrence lobjet effectuant lopration. Par exemple (void) textFieldDidBegin

4.1. Mcanisme de dlgation

101

Editing: (UITextField *)textField pour notier au dlgu que le champ de texte vient dentrer en mode dition.

Figure 4.1 : Outlet delegate dun objet UITextField

Une demande dautorisation est trs souvent un message qui renvoie une valeur de type BOOL. Si le dlgu autorise lopration, il renvoie YES ; autrement, il renvoie NO. Par exemple (BOOL) textFieldShouldBeginEditing: (UITextField *)textField pour demander au dlgu si le champ de texte peut entrer en mode dition.

Type BOOL
BOOL est un type prdni dans Objective-C qui reprsente une valeur
logique ou boolenne. Les deux seules valeurs que peut prendre une variable de type BOOL sont YES et NO.

Dlguer le champ dollar


Nous allons apporter une premire amlioration dans Convertisseur1 que nous perfectionnerons par la suite. Notre objectif sera de limiter la frappe aux caractres numriques dans le champ de texte contenant la valeur en dollars.
102
4. Motifs fondamentaux

Cration du dlgu
1 Ouvrez le chier Convertisseur1ViewController.xib sous Interface Builder et connectez loutlet delegate du champ de texte lobjet Files Owner.

Figure 4.2 : Dnir Convertisseur1ViewController comme dlgu du champ dollar

Le contrleur de vue comme dlgu


Il est courant de dnir le contrleur de vue comme dlgu des objets contenus dans cette vue principale, surtout dans les applications simples.

2 Sous XCode, modiez le chier Convertisseur1ViewController.h pour indiquer que cette classe est aussi un dlgu de champ de texte :
#import <UIKit/UIKit.h> @interface Convertisseur1ViewController : UIViewController <UITextFieldDelegate> { IBOutlet UITextField *labelDollar; IBOutlet UITextField *labelEuro; } @property (retain,nonatomic) UITextField *labelDollar; @property (retain,nonatomic) UITextField *labelEuro; - (IBAction) changeValue; @end

3 Ajoutez la dnition de la mthode suivante dans le chier Convertisseur1ViewController.m :


- (BOOL)textField:(UITextField *)textField

4.1. Mcanisme de dlgation

103

shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string { return [[NSCharacterSet decimalDigitCharacterSet] isSupersetOfSet:[NSCharacterSet characterSetWithCharactersInString:string]]; }

La mthode textField:shouldChangeCharactersInRange:replacement String est invoque sur le dlgu chaque fois que lutilisateur modie le contenu du champ de texte. Le paramtre range (intervalle) indique quel endroit dans le texte existant la modication sera effectue et ventuellement quels sont les caractres qui seront supprims. Le paramtre string contient la chane de caractres que lutilisateur souhaite insrer ou ajouter au champ de texte.

Classe NSCharacterSet
Nous en protons pour faire connaissance avec la classe permettant de manipuler des ensembles de caractres, NSCharacterSet, et trois de ses mthodes :
j

+decimalDigitCharacterSet construit lensemble de caractres form des chiffres de 0 9. +characterSetWithCharactersInString: construit lensemble des caractres inclus dans la chane de caractres passe en paramtre. isSuperSetOf: retourne YES si lensemble pass en paramtre est inclus dans lensemble rcepteur.

La dmarche pour vrier que lutilisateur saisit uniquement des chiffres est la suivante : 1 Constituez un ensemble de caractres compos des caractres saisis. 2 Constituez lensemble des caractres numriques (chiffres). 3 Vriez que le premier ensemble est inclus dans le second.

Taille de la saisie de caractres


On pourrait simplier lcriture de cette mthode de dlgu en supposant que lutilisateur ne peut saisir quun caractre la fois ; il suffirait de tester si ce caractre est compris entre 0 et 9. Malheureusement, cette simplication serait errone car lutilisateur peut coller un texte pralablement copi et donc "saisir" plusieurs caractres en une fois dans un champ de texte.

104

4. Motifs fondamentaux

Figure 4.3 : Saisie de plusieurs caractres

4 Reconstruisez lapplication et testez-la sur le simulateur. Vriez que vous ne pouvez plus saisir de lettres ni de signes de ponctuation. Notre dlgu fonctionne.

Dlgu pour un champ de texte


Dans la section prcdente, nous avons dni lobjet Convertisseur1 ViewController comme dlgu du champ de texte contenant le montant en dollars, puis nous y avons ajout une mthode. Nous allons dtailler ici toutes les mthodes que lon pourrait crire au besoin.

Mthodes du dlgu
Son dlgu est interrog par un champ de texte lors des situations suivantes pour savoir si :
j j

ldition peut commencer ; ldition peut se terminer, cest loccasion de vrier la validit du texte saisi par lutilisateur et dalerter ce dernier si le champ nest pas correctement saisi ; le texte peut tre modi lors de chaque opration de saisie, cest cette situation que nous venons dutiliser ; le texte peut tre effac en dbut de saisie ;
4.1. Mcanisme de dlgation

105

laction conscutive la frappe de la touche [] est autorise.

Le dlgu est galement inform dans les situations suivantes ; cela lui permet ainsi deffectuer des actions complmentaires que ne saurait pas faire le champ de texte :
j j

Ldition vient de commencer. Ldition vient de se terminer.

Le tableau ci-aprs rsume les messages mis vers le dlgu par le champ de texte dans chacune de ces situations. Pour chaque message, la dclaration prcise de la mthode est indique.
Tableau 4.1 : Mthodes du protocole UITextFieldDelegate Signature de la mthode Objet de la mthode

(BOOL)textFieldShouldBegin Demande au dlgu si ldition du champ de Editing:(UITextField *)textField texte peut commencer. (void)textFieldDidBegin Informe le dlgu que ldition du champ de Editing:(UITextField *)textField texte vient de commencer. (BOOL)textFieldShouldEnd Demande au dlgu si ldition du champ de Editing:(UITextField *)textField texte peut se terminer. (void)textFieldDidEnd Informe le dlgu que ldition du champ de Editing:(UITextField *)textField texte vient de se terminer. (BOOL)textField:(UITextField *) Demande au dlgu si le texte peut tre textField shouldChangeCharacter- modi. sInRange:(NSRange)range replacementString:(NSString *)string (BOOL)textFieldShouldClear: (UITextField *)textField (BOOL)textFieldShouldReturn: (UITextField *)textField
Demande au dlgu si le contenu du champ de texte peut tre effac. Demande au dlgu sil faut utiliser le comportement par dfaut de la touche [] qui vient dtre frappe.

Toutes les mthodes prennent un paramtre textField. Le champ de texte communique systmatiquement une rfrence sur lui-mme son dlgu. Cela permet un objet dtre le dlgu de plusieurs autres objets ; il sait qui lui transmet un message.

Mthodes optionnelles
Dans notre classe Convertisseur1ViewController, nous avons crit seulement lune des 7 mthodes dnies pour un dlgu de champ de texte. Voici une caractristique intressante du langage Objective-C : dans de nombreux autres langages, nous aurions t obligs dcrire les 7 mthodes dont 6 qui ne faisaient rien.

106

4. Motifs fondamentaux

Comment fait le champ de texte pour savoir sil peut ou non mettre un message vers son dlgu ?

Appel de mthode inexistante


Lappel dune mthode inexistante sur un objet provoque gnralement le plantage de lapplication et la leve de lexception EXC_BAD_INSTRUCTION.

respondsToSelector
La classe NSObject, de laquelle drive directement ou indirectement toutes les autres classes, dnit une mthode respondsToSelector: disponible pour tous les objets.
- (BOOL) respondsToSelector:(SEL)aSelector

Le type SEL est un slecteur, cest--dire un pointeur sur une mthode. La primitive @selector dObjective-C permet dobtenir un slecteur partir du nom complet dune mthode (sans les types ni les noms de paramtres). Ainsi le champ de texte peut interroger le dlgu pour savoir sil rpond une mthode avant de lui transmettre un message.
SEL aSelector = @selector( textField:shouldChangeCharactersInRange:replacementString:); if ( [delegate respondsToSelector:aSelector] )

Dclarer un protocole
Adopter un protocole
Souvenez-vous de la petite modication que nous avons effectue dans le chier Convertisseur1ViewController.h :
@interface Convertisseur1ViewController : UIViewController <UITextFieldDelegate> {

Lajout de <UITextFieldDelegate> permet de prciser que la classe que nous dclarons adopte le protocole UITextFieldDelegate. Nous pouvons spcier une liste de protocoles entre les crochets, en les sparant par une virgule.

Protocole
Un protocole est une liste de dclarations de mthodes, certaines requises dautres optionnelles. Cette liste nest pas attache a priori une classe particulire. Il appartient la classe qui adopte un protocole de dnir toutes les mthodes requises et les mthodes optionnelles ncessaires. Les protocoles Objective-C sont quivalents aux interfaces Java.

4.1. Mcanisme de dlgation

107

Les frameworks de Cocoa Touch dnissent un protocole pour chaque type de dlgu. Par exemple, la classe UITextField a besoin dun objet dlgu qui adopte le protocole UITextFieldDelegate. Lorsque vous dnissez un objet qui doit tre un dlgu, noubliez pas dindiquer le protocole quil adopte.

Dnir un protocole
Vous pouvez dnir vos propres protocoles laide des mots-cls @protocol, @optional et @end :
@protocol nom-du-protocole // Dclarations des mthodes requises @optional // Dclarations des mthodes optionnelles @end

Par exemple, le protocole UITextFieldDelegate pourrait tre dclar comme suit :


@protocol UITextFieldDelegate @optional - (BOOL)textFieldShouldBeginEditing:(UITextField*)textField; - (void)textFieldDidBeginEditing:(UITextField *)textField; - (BOOL)textFieldShouldEndEditing:(UITextField *)textField; - (void)textFieldDidEndEditing:(UITextField *)textField; - (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string; - (BOOL)textFieldShouldClear:(UITextField *)textField; - (BOOL)textFieldShouldReturn:(UITextField *)textField; @end

Lancement de lapplication
Les autres dlgus
Nous avons dtaill le protocole du dlgu pour un champ de texte. Les frameworks de Cocoa Touch proposent une quarantaine de protocoles de dlgu ; tous portent un nom qui se termine par Delegate. Il est important de bien comprendre le mcanisme de dlgation. En effet, ce sont des objets dlgus que le programmeur Cocoa Touch crera pour modier le comportement des objets standard fournis par Apple : vues, contrleurs, etc.

108

4. Motifs fondamentaux

Vous tes-vous aperu que nous avons utilis un autre dlgu ? Celui de la classe UIApplication. Nous allons examiner dans cette section ce qui se passe lorsquon lance lapplication. Pour cela, nous ferons connaissance avec le protocole UIApplicationDelegate.

UIApplication
Regardez sous XCode le contenu du chier main.m :
#import <UIKit/UIKit.h> int main(int argc, char *argv[]) { NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; int retVal = UIApplicationMain(argc, argv, nil, nil); [pool release]; return retVal; }

Vous naurez gnralement pas modier ce code mais il est intressant de comprendre le rle de cette fonction. Sous un systme de la famille UNIX, tel que Linux, iPhone OS ou MacOSX, toute application doit contenir une fonction main appele lors de son lancement. Cette fonction ralise les oprations suivantes :
j

cration dun pool dautolibration principal pour lapplication lapplication (rappelez-vous quil sert librer les instances dont la dure de vie est limite une boucle dvnements) ; appel de la fonction UIApplicationMain qui va effectuer tout le travail : cration dun objet de la classe UIApplication ; chargement du chier MainWindow.xib dont lobjet UIApplication sera propritaire ; cration de la boucle dvnement ; lancement de la boucle dvnement tant que lapplication na pas t quitte ; fonction termine lorsque lapplication est quitte.

libration du pool dautolibration puisque lapplication se termine ; Fin de lapplication.

MainWindow.nib
Le chier MainWindow.xib est donc charg au lancement de lapplication. Jetons un coup dil dans ce chier laide dInterface Builder.

4.1. Mcanisme de dlgation

109

Nom du fichier NIB principal


Le nom du chier NIB principal est la valeur de la proprit Main nib le base name du chier Info.plist de lapplication. XCode le dnit par dfaut MainWindow, il est possible de le changer.

Le chier NIB principal contient 5 objets :


j

Le propritaire (Files Owner) comme dans tout chier NIB. Il est ici de type UIApplication puisque il doit tre charg par lapplication. Le premier rpondeur (First Responder) galement comme dans tout chier NIB. Cet objet reprsente la vue de linterface en cours ddition par lutilisateur. On utilise cet objet comme cible pour des actions que lon veut transmettre cette vue. Un objet Window de type UIWindow. Cet objet est la fentre de lapplication dans laquelle toutes les vues seront affiches. Convertisseur1 App Delegate, de type Convertisseur1AppDelegate, que nous allons examiner. Convertisseur1 View Controller de type Convertisseur1View Controller que nous connaissons dj car nous avons modi cette classe.

Figure 4.4 : Contenu de MainWindow.nib

Toujours sous Interface Builder, examinez les connexions entre ces diffrents objets (voir Figure 4.5). Au chargement du chier MainWindow.xib, les objets du chier sont crs et relis entre eux en utilisant les outlets (voir Figure 4.6).

110

4. Motifs fondamentaux

Figure 4.5 : Connexions dans MainWindow.xib

Figure 4.6 : Structure dobjets cre au chargement de MainWindow.xib

Le dlgu de lapplication est cr et li lapplication ce momentl.

Dlgu dapplication
Nous connaissons le contrleur de vue Convertisseur1ViewController. Faisons connaissance au dlgu dapplication que XCode a cr pour nous. Regardez le contenu du chier Convertisseur1AppDelegate.h :
#import <UIKit/UIKit.h> @class Convertisseur1ViewController; @interface Convertisseur1AppDelegate : NSObject <UIApplicationDelegate> { UIWindow *window; Convertisseur1ViewController *viewController;

4.1. Mcanisme de dlgation

111

} @property (nonatomic, retain) IBOutlet UIWindow *window; @property (nonatomic, retain) IBOutlet Convertisseur1ViewController *viewController; @end

Seule linstruction @class est nouvelle. Nous savons dj interprter les autres lignes de code :
j

Une classe Convertisseur1AppDelegate est dclare, qui hrite de NSObject et adopte le protocole UIApplicationDelegate ; il sagit dun dlgu dapplication. Les outlets window et viewController sont dclars ; ce sont ceux utiliss dans le chier MainWindow.xib pour relier cette classe aux autres objets du chier NIB.

@class
La clause @class permet didentier un nom comme tant celui dune classe. Ce nom pourra ensuite tre utilis pour dclarer des objets de cette classe. On utilise @class nomdelaclasse; lorsquon veut simplement dclarer des objets de cette classe, sans les utiliser. On emploie #import "nomdelaclasse.h" lorsquon veut utiliser des objets de cette classe, leur transmettre des messages.

O en sommes-nous dans le processus de lancement de lapplication ?


j j j

Un pool dautolibration a t cr. Un objet UIApplication a t cr et il est activ. Le chier MainWindow.nib a t charg et une structure dobjets a t cre qui comprend : une fentre (window) pour lapplication ; un dlgu (Convertisseur1AppDelegate) ; un contrleur de vue (Convertisseur1ViewController).

Lapplication est sur le point de lancer la boucle dvnement. Auparavant, elle va informer son dlgu que le lancement vient de se terminer en mettant le message applicationDidFinishLaunching. Examinons le code source du dlgu dapplication, chier Convertisseur1AppDelegate.m :

112

4. Motifs fondamentaux

#import "Convertisseur1AppDelegate.h" #import "Convertisseur1ViewController.h" @implementation Convertisseur1AppDelegate @synthesize window; @synthesize viewController; - (void)applicationDidFinishLaunching:(UIApplication *) application { // Override point for customization after app launch [window addSubview:viewController.view]; [window makeKeyAndVisible]; } - (void)dealloc { [viewController release]; [window release]; [super dealloc]; } @end

Le dlgu affiche la vue contrle par notre instance de Convertisseur1ViewController puis la fentre est affiche et active sur lcran de lappareil. Quest-ce qui est affich lcran prcisment ? Examinez le contrleur de vue dans le chier MainWindow.xib sous Interface Builder.

Figure 4.7 : Convertisseur1ViewController dans MainWindow.xib

4.1. Mcanisme de dlgation

113

Le chargement du chier NIB MainWindow.xib cre un objet Convertisseur1ViewController associ au chier NIB Convertisseur1 ViewController.xib. Cest lutilisation de la proprit view du contrleur de vue qui provoque le chargement du chier NIB associ.

Structurer une application


Ce principe peut tre tendu la plupart des applications sur iPhone OS :
j

Lapplication charge un chier NIB qui contient : une fentre et ventuellement des vues ; gnralement un dlgu pour le propritaire du chier NIB ; un ou plusieurs contrleurs de vue.

Chaque contrleur de vue possde lui-mme un chier NIB qui contient : une hirarchie de vue lintrieur de sa vue principale ; son tour, un ou plusieurs contrleurs de vue ; ventuellement dautres objets.

Chaque contrleur peut galement possder un chier NIB, etc.

Figure 4.8 : Structuration classique dune application

114

4. Motifs fondamentaux

4.2. Amliorer Convertisseur1


Nous avons russi mettre en uvre le dlgu pour limiter la frappe aux seuls chiffres mais le rsultat nest pas trs satisfaisant, en tout cas loin dune application professionnelle :
j j

Il ny a plus moyen de saisir des chiffres aprs la virgule. Ce nest mme pas une virgule, cest un point qui saffiche pour sparer les centimes. Toujours pas moyen de se dbarrasser du clavier qui reste btement affich tout le temps. Le nom de lapplication ne saffiche pas en entier sous le logo. La moindre des choses serait de pouvoir faire les conversions dans les deux sens.

j j

Nous avons du pain sur la planche ; ne tranons pas.

Retrouver la virgule
Si nous voulons pouvoir saisir un point dcimal ou une virgule, il faut autoriser la frappe de lun de ces caractres dans le dlgu du champ de texte. Ce nest pas si simple ; on pourrait alors saisir plusieurs virgules, ce qui nest pas autoris pour reprsenter un nombre. Il serait plus simple de vrier au fur et mesure de la saisie que la chane de caractres obtenue est la reprsentation dun nombre. Et pour le vrier, le plus simple est de convertir cette chane en nombre. Puisquil faut conomiser les ressources prcieuses de liPhone, vitez deffectuer cette conversion une fois dans la mthode du dlgu et juste aprs dans la mthode changeValue. Nous allons crer un objet dont le rle sera deffectuer cette vrication, la conversion en nombre et la conversion en dollars.

Objet Convertisseur
1 Crez un nouveau chier de type classe Objective-C sous XCode, en slectionnant la commande New File du menu File (X+[N]). Nommez-le Convertisseur.m et cochez la case Also create "Convertisseur.h" (voir Figure 4.9).

4.2. Amliorer Convertisseur1

115

Figure 4.9 : Crer une classe Objective-C

2 Modiez le chier Convertisseur.h comme suit :


#import <Foundation/Foundation.h> @interface Convertisseur : NSObject { float euro; float dollar; float dollarsPourUnEuro; } @property (nonatomic,assign) float euro; @property (nonatomic,assign) float dollar; @property (nonatomic,assign) float dollarsPourUnEuro; - (BOOL) setDollarWithString: (NSString *) string; @end

Notre intention est que la mthode setDollarWithString: retourne YES si la chane string reprsente un montant en dollars. Dans ce cas, il est aussi converti en euros. Si ce nest pas le cas, la mthode doit retourner NO et les valeurs euro et dollar ne sont pas modies. Il faudra aussi initialiser la proprit dollarsPourUnEuro quelque part ; dans la mthode init de la classe, cest le plus simple. 3 Modiez le chier Convertisseur.m :
#import "Convertisseur.h" @implementation Convertisseur @synthesize euro; @synthesize dollar; @synthesize dollarsPourUnEuro;

116

4. Motifs fondamentaux

-(id) init { if (self = [super init]) { self.dollarsPourUnEuro = 1.4908; } return self; } -(BOOL) setDollarWithString:(NSString *)string { float valeur; BOOL result; NSScanner *scan = [NSScanner localizedScannerWithString:string]; [scan scanFloat:&valeur]; result = [scan isAtEnd]; if (result) self.dollar = valeur; return result; } -(void) setDollar:(float)newValue { dollar = newValue; euro = newValue / dollarsPourUnEuro; } @end

Classe NSScanner
Nous rencontrons la classe NSScanner pour la premire fois. Cest une chane de caractres laquelle on a ajout un curseur (proprit scanLocation) initialis 0 la cration dune instance. Chaque fois quune instance de NSScanner reoit un message de conversion (par exemple scanFloat:), le curseur progresse jusquau prochain caractre qui ne peut participer la conversion. Une conversion est effectue partir de la position du curseur. Ainsi, la chane passe en paramtre la mthode setDollarWithString: est un nombre si le curseur est la n de la chane aprs la conversion. Nous avons ici une petite particularit : les mthodes de conversion telle que scanFloat: retourne 2 valeurs :
j

La valeur de retour est un BOOL qui indique si la conversion est russie (que nous nutilisons pas ici). Une valeur convertie au format souhait (float pour scanFloat:).

Le paramtre pass scanFloat: est &valeur et pas simplement valeur. Comme nous souhaitons rcuprer une valeur dans la variable valeur, ce nest pas sa valeur quil faut passer mais ladresse de la variable. Nous utilisons donc &, loprateur de rfrencement du langage C.
4.2. Amliorer Convertisseur1

117

Oprateur de rfrencement
Ladresse dune variable sobtient en utilisant loprateur & juste avant le nom de la variable.

Dclarer une proprit Convertisseur


Nous avons cr une classe Convertisseur. Pour lutiliser, il faut en dclarer une instance dans un des objets de notre application. Le plus logique est de la crer dans la classe Convertisseur1 ViewController, cest l que nous en aurons besoin. Nous allons donc ajouter une proprit dans notre contrleur de vue. 1 Modiez le chier Convertisseur1ViewController.h :
#import <UIKit/UIKit.h> @class Convertisseur; @interface Convertisseur1ViewController : UIViewController <UITextFieldDelegate> { IBOutlet UITextField *labelDollar; IBOutlet UITextField *labelEuro; Convertisseur *convertisseur; } @property (retain,nonatomic) UITextField *labelDollar; @property (retain,nonatomic) UITextField *labelEuro; @property (retain,nonatomic) Convertisseur *convertisseur; - (IBAction) changeValue; @end

2 Dans le chier Convertisseur1ViewController.m, modiez les mthodes viewDidLoad (enlevez les commentaires /* et */) et viewDidUnload :
// Implement viewDidLoad to do additional setup after // loading the view, typically from a nib. - (void)viewDidLoad { [super viewDidLoad]; convertisseur = [[Convertisseur alloc] init]; } - (void)viewDidUnload { // Release any retained subviews of the main view. // e.g. self.myOutlet = nil; self.labelDollar = nil; self.labelEuro = nil; self.convertisseur = nil; }

118

4. Motifs fondamentaux

3 Noubliez pas dajouter #import "Convertisseur.h" en tte du chier et @synthesize convertisseur; avec les autres synthtiseurs de proprit. La mthode viewDidLoad est invoque la n du chargement du chier NIB du contrleur de vue. Cest le bon endroit pour effectuer les initialisations du contrleur ; on est certain que toutes les vues sont cres et que les outlets sont utilisables si besoin.

Modier le dlgu
Modiez la mthode de dlgu dans le chier Convertisseur1
ViewController.m :
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string { NSString *resultingString = [textField.text stringByReplacingCharactersInRange:range withString:string]; return [self.convertisseur setDollarWithString:resultingString]; }

Nous constituons une chane de caractres resultingString dont la valeur est celle quaura le champ de texte aprs lui avoir appliqu la modication demande par lutilisateur. Ensuite, nous utilisons notre instance de Convertisseur pour vrier que lon peut effectuer la conversion.

Modier laction
1 Modiez la mthode changeValue dans le chier Convertisseur1 ViewController.m. Cette mthode devient beaucoup plus simple car le travail de conversion est maintenant effectu par la classe Convertisseur :
- (IBAction) changeValue { NSString *textEuro = [NSString localizedStringWithFormat: @"%.2f",self.convertisseur.euro]; labelEuro.text = textEuro; }

textEuro nest plus libr


Linstance textEuro ntant plus cre par la mthode +alloc, nous savons quelle est dans le pool dautolibration. Il ne faut donc pas la librer explicitement, sauf si nous la retenions, ce qui nest pas le cas ici.

2 Reconstruisez et testez lapplication.


4.2. Amliorer Convertisseur1

119

Localiser lapplication
Localiser les montants
Vous avez remarqu deux des nouvelles mthodes que nous avons utilises :
j j

+localizedScannerWithString: de la classe NSScanner ; +localizedStringWithFormat: de la classe NSString.

Chane localise
Une chane de caractres localise est un texte dont le format prcis dpend des rglages rgionaux de lappareil. Les textes localiss concernent les dates, les heures, les numros de tlphone et les nombres virgule. Le sparateur dcimal est une virgule en France et un point dans les pays anglo-saxons.

Pour vrier si la localisation des montants en euros et en dollars fonctionne, nous allons modier les rglages du simulateur diPhone. 1 Lancez lapplication Settings (ou Rglages si le simulateur est rgl en franais).

Figure 4.10 : Application Settings sur le simulateur

120

4. Motifs fondamentaux

2 Choisissez Gnral puis International. Loption Format rgional (Region Format) vous permet de changer le paramtre rgional du simulateur. Vous pouvez en proter aussi pour changer la langue de liPhone OS.

Figure 4.11 : Localisation du simulateur

3 Testez lapplication dans les formats rgionaux France et tats-Unis pour vrier que le sparateur des nombres dcimaux est une virgule ou un point suivant le cas.

Figure 4.12 : Test pour les rgions tats-Unis et France 121

4.2. Amliorer Convertisseur1

Localiser linterface utilisateur


Nous venons de voir comment prendre en compte les paramtres rgionaux pour mettre en forme les nombres ; pensez aux mthodes contenant le terme localized dans leur nom. Pour localiser vraiment lapplication, il faut aussi que linterface utilisateur soit prsente dans sa langue. Nous localiserons donc le chier NIB de la vue principale. 1 Sous XCode, slectionnez le chier Convertisseur1View Controller.xib et cliquez du bouton droit pour afficher le menu contextuel. Slectionnez la commande Get Info.

Figure 4.13 : Afficher les informations relatives au chier NIB

2 Dans la fentre dinformations qui saffiche, cliquez sur le bouton Make File Localizable.

Figure 4.14 : Crer une version localise du chier NIB 122

4. Motifs fondamentaux

La fentre change de titre car nous venons de crer un groupe localis. 3 Dans longlet General, cliquez sur le bouton Add Localization pour crer une version franaise (French) en plus de la version anglaise (English) existante.

Figure 4.15 : Le groupe localis contient une version franaise et une version anglaise

Comme notre version actuelle est en franais, la version franaise du chier NIB est correcte et il faut modier la version anglaise. 4 Fermez la fentre dinformation et sous XCode, double-cliquez sur la version anglaise du chier Convertisseur1ViewController.xib (English) pour louvrir sous Interface Builder. Interface Builder est muni dun outil trs pratique pour raliser les traductions. 5 Activez la commande Strings du menu Tools. Une fentre saffiche qui prsente toutes les chanes de caractres contenues dans le chier NIB. 6 Saisissez les traductions dans la colonne Value pour chacune des chanes de caractres : Currency Converter, US $ amount et Euros amount.
4.2. Amliorer Convertisseur1

123

Figure 4.16 : Menu Tools dInterface Builder

Figure 4.17 : Traduction des chanes de caractres du chier NIB

7 Enregistrez le chier NIB et revenez sous XCode. Avant de reconstruire lapplication, il faut nettoyer les constructions prcdentes. Autrement, la version non localise du chier NIB continuera tre installe et utilise. 8 Slectionnez la commande Clean All Targets du menu Build. 9 Dans la bote de dialogue qui saffiche, cochez toutes les cases et cliquez sur Clean.

Figure 4.18 : Nettoyage des constructions prcdentes

124

4. Motifs fondamentaux

10 Reconstruisez lapplication et testez-la avec le simulateur diPhone. Essayez-la avec les paramtres rgionaux US, UK et France et dans les langues anglaise et franaise.

Figure 4.19 : Application localise

Nettoyage (Clean)
Lorsque nous modions la liste des ressources de lapplication, il est prudent de faire un nettoyage des constructions an que les ressources devenues inutiles ne perturbent pas le fonctionnement de lapplication.

Utiliser le motif KVC


Il est regrettable que notre convertisseur ne fonctionne que dans un sens, des dollars vers les euros. Remdions cela. Nous aurons ainsi lopportunit daborder le puissant codage par valeur de cl (KVC, Key Value Coding).

Adapter la classe Convertisseur


1 Ajoutez une mthode setEuro: dans le chier Convertisseur.m pour effectuer la conversion en dollars. Cette mthode est analogue setDollar: :

4.2. Amliorer Convertisseur1

125

-(void) setEuro:(float)newValue { euro = newValue; dollar = newValue * dollarsPourUnEuro; }

setEuro est dj dclar par @property


Il nest pas utile de dclarer setEuro: dans linterface de la classe car euro est dj dclar comme une proprit. Nous crivons en fait un manipulateur qui remplace celui cr par dfaut par la clause @synthesize.

Il faudrait galement ajouter une mthode setEuroWithString: qui serait analogue setDollarWithString:. Nous allons plutt modier la mthode existante pour quelle fonctionne dans les deux cas. Souvenez-vous ; il faut essayer de factoriser le code pour quil soit plus facile maintenir. 2 Modiez le chier Convertisseur.h. Remplacez la dclaration de la mthode setDollarWithString: par la mthode suivante.
- (BOOL) setValueForKey:(NSString *)key WithString: (NSString *) string;

Notre intention est dutiliser le paramtre key pour transmettre le nom de la proprit modier, euro ou dollar. 3 Modiez la mthode setDollarWithString: dans le chier Convertisseur.m.
-(BOOL) setValueForKey:(NSString *)key WithString:(NSString *)string { float valeur; BOOL result; NSScanner *scan = [NSScanner localizedScannerWithString:string]; [scan scanFloat:&valeur]; result = [scan isAtEnd]; if (result) [self setValue:[NSNumber numberWithFloat:valeur] forKey:key]; return result; }

Key Value Coding


Objective-C et NSObject nous proposent daccder aux proprits dun objet en donnant le nom de la proprit dans une chane de caractres.

126

4. Motifs fondamentaux

Accs par mthodes

Accs par cl

(id) property (void) setProperty:(id) value

(id) valueForKey: @"property" (void) setValue:(id)value forKey: @"property"

Les mthodes valueForKey: et setValue:forKey: appellent respectivement laccesseur et le manipulateur par dfaut de la proprit dont le nom est pass dans le paramtre key. Il est donc indispensable dutiliser la rgle standard de dnomination pour que le KVC fonctionne. Les mthodes du KVC manipulent des valeurs de type id, cest--dire une rfrence une instance dobjet. Lorsque les proprits sont de type scalaire (int, oat, etc.), il faut les encapsuler dans un objet NSNumber. Les mthodes du KVC ralisent les conversions appropries entre les instances de NSNumber et les valeurs scalaires.

Modier le dlgu
Nous avons modi la classe Convertisseur, il faut donc prendre en compte ce changement dans la mthode de dlgu de champ de texte que nous avons crite dans la classe Convertisseur1 ViewController. De plus, nous voulons maintenant ragir aux actions de lutilisateur dans le champ de texte contenant le montant en euros. Modiez la mthode de dlgu dans le chier Convertisseur1
ViewController.m :
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string { NSString *resultingString = [textField.text stringByReplacingCharactersInRange:range withString:string]; if (textField==labelDollar) return [self.convertisseur setValueForKey:@"dollar" withString:resultingString]; else return [self.convertisseur setValueForKey:@"euro" withString:resultingString]; }

Nous utilisons ici le paramtre textField de la mthode dlgu pour identier quel champ de texte a transmis le message.

4.2. Amliorer Convertisseur1

127

Constante NSString
Nous utilisons ici la notation @".." qui permet de dnir une constante de type NSString, par exemple @"dollar". En Objective-C, on utilise beaucoup plus souvent les constantes NSString que les chanes de caractres C et la notation "..".

Modier laction
La mthode changeValue doit galement tre modie car les deux champs de texte sont susceptibles de linvoquer. Nous emploierons une autre variante du prototype daction (IBAction) action: (id)sender. Le paramtre sender est lobjet qui a dclench laction. 1 Modiez le chier Convertisseur1ViewController.h pour utiliser ce nouveau prototype daction :
@interface Convertisseur1ViewController : UIViewController <UITextFieldDelegate> { IBOutlet UITextField *labelDollar; IBOutlet UITextField *labelEuro; Convertisseur *convertisseur; } @property (retain,nonatomic) UITextField *labelDollar; @property (retain,nonatomic) UITextField *labelEuro; @property (retain,nonatomic) Convertisseur *convertisseur; - (IBAction) changeValue:(id)sender; @end

2 Modiez le code de la mthode changeValue dans le chier Convertisseur1ViewController.m :


- (IBAction) changeValue:sender { NSString *textEuro; if (sender==labelDollar) { textEuro = [NSString localizedStringWithFormat: @"%.2f",self.convertisseur.euro]; labelEuro.text = textEuro; } else { textEuro = [NSString localizedStringWithFormat: @"%.2f",self.convertisseur.dollar]; labelDollar.text = textEuro; } }

3 Enregistrez les chiers modis sous XCode. Vous pouvez galement reconstruire lapplication pour vrier que le code saisi est correct.

128

4. Motifs fondamentaux

tablir les connexions


Il faut maintenant tablir les connexions dans le chier NIB de la vue principale.

Fichiers NIB localiss


Il faut effectuer les mmes modications dans toutes les versions localises dun chier NIB. Il est parfois plus facile de commencer par supprimer les localisations puis effectuer les modications dans une version unique pour enn recrer les versions localises partir du chier NIB unique. Citons aussi loutil ibtool dont la description sort de cadre de cet ouvrage. Il permet dautomatiser en partie la localisation des diffrentes modications dun chier NIB.

1 Ouvrez successivement chacune des versions localises du chier Convertisseur1ViewController.xib sous Interface Builder pour tablir les connexions des actions et des dlgus. Par prudence, puisque nous venons de modier la classe Convertisseur1 ViewController, nous pouvons recharger les dclarations des classes utilises sous Interface Builder. 2 Slectionnez la commande Reload All Class Files du menu File. 3 Dans chacune des versions du chier NIB, slectionnez successivement les deux champs de texte pour tablir les connexions avec le propritaire du chier : loutlet delegate ; lvnement Editing Changed sur laction changeValue:. 4 Reconstruisez lapplication et testez-la. La conversion fonctionne dans les deux sens.

Autres amliorations
Nous terminerons cette nouvelle version de lapplication Convertisseur1 par quelques amliorations simples.

Voir le nom entier


Le nom de lapplication Convertisseur1 est trop long ; il ne saffiche pas entier sous son logo sur liPhone.

4.2. Amliorer Convertisseur1

129

Nous allons en changer pour un nom plus court, par exemple ConvertPro.

1 Dans la zone Groups & Files, sous XCode, slectionnez la cible Convertisseur1 dans le groupe Targets, cliquez du bouton droit et activez la commande Get info pour afficher les informations relatives lapplication Convertisseur1.

Figure 4.20 : Afficher les informations de lapplication

2 Slectionnez longlet Build de la fentre dinformation qui est apparue. Saisissez name dans le champ de recherche pour limiter la liste des paramtres affichs et recherchez le paramtre Product Name.

Figure 4.21 : Modier le nom de lapplication

3 Double-cliquez sur ce paramtre et saisissez le nom souhait, par exemple ConvertPro.

130

4. Motifs fondamentaux

4 Reconstruisez lapplication pour vrier que le nom saffiche sous le logo.

Effacer le clavier
Nous souhaitons que le clavier disparaisse lorsque lutilisateur presse la touche Termin (Done en anglais) sur le clavier. La frappe de cette touche provoque lmission de lvnement Did End On Exit par le champ de texte. Il nous faut donc crer une nouvelle action, appelons-la doneEditing, dans Convertisseur1 ViewController. 1 Modiez la classe Convertisseur1ViewController pour dclarer cette nouvelle action puis liez lvnement Did End On Exit des deux champs de texte cette action. Noubliez pas denregistrer le chier modi sous XCode et de recharger les chiers de classe sous Interface Builder.
- (IBAction) changeValue:(id)sender; - (IBAction) doneEditing:(id)sender; @end

Figure 4.22 : Champs de texte connects la nouvelle action

2 Saisissez le code de laction. Reconstruisez lapplication et testezla.


- (IBAction) doneEditing:(id)sender { [sender resignFirstResponder]; }

Nous arrivons maintenant effacer le clavier.

4.2. Amliorer Convertisseur1

131

Figure 4.23 : Le clavier est escamotable

La mthode resignFirstResponder est dnie dans la classe UIResponder. Cette classe gre la chane des rpondeurs.

Figure 4.24 : Chane des rpondeurs

La chane des rpondeurs est constitue par les vues, les contrleurs de vue, la fentre dapplication et lapplication. Le premier rpondeur-

132

4. Motifs fondamentaux

(First responder) est gnralement la vue, ou le contrle puisque UIControl hrite de UIView, actif un moment donn. Lorsque lutilisateur touche le champ de texte dollar, ce dernier devient le premier rpondeur. Lapplication transmet les actions au premier rpondeur. Cest lobjet actif un moment donn qui est le mieux plac pour rpondre une action. Si le premier rpondeur, gnralement une vue, ne sait pas traiter laction, cette dernire est transmise au rpondeur suivant dans la chane, etc. La chane de rpondeurs remonte la hirarchie des vues partir du premier rpondeur. Une vue transmet une action son contrleur (si elle en possde un) avant de la transmettre sa supervue. Si un champ de texte reoit le message resignFirstResponder, il devient inactif et le clavier disparat alors.

4.3. Motif MVC


Regardons la structure gnrale de lapplication que nous avons produite.

Figure 4.25 : Structure MVC de lapplication Convertisseur1

Nous pouvons identier trois parties distinctes :


j

Le Modle ; cest lensemble des classes qui grent les donnes de

lapplication, on les appelle les objets mtiers. Pour lapplication


Convertisseur1, il est constitu de la seule classe Convertisseur.
j

La Vue ; compose de la hirarchie des vues et de la fentre de

lapplication.
j

Les Contrleurs ; qui comportent les contrleurs de vue et lappli-

cation.

4.3. Motif MVC

133

Les contrleurs connaissent les parties Vue et Modle ; la classe Convertisseur1ViewController connat les outlets labelDollar et labelEuro (Vue), et la proprit Convertisseur (Modle). Il ny a en revanche aucune communication directe entre les vues et le modle. Ce motif de conception est nomm Modle-Vue-Contrleur (MVC, Model-View-Controller). Il consiste identier le rle de chaque classe avec lobjectif de faciliter la rutilisation des objets (Vue et Modle) ainsi que les tests. Les objets composant la Vue sont des briques utilisables telles quelles dans toutes les applications. Ces briques sont indpendantes des objets mtiers. Veillez ce que les classes mtiers (celles du Modle) naient connatre ni les vues, ni les contrleurs. Cest la garantie de pouvoir les rutiliser dans dautres applications.

4.4. Challenges
Nous avons suffisamment avanc maintenant pour que vous puissiez crer de petites applications simples.

Amliorer encore Convertisseur1


Notre application est dj dun bon niveau mais il reste encore un comportement qui peut tre dsagrable pour lutilisateur. Lorsquon entre en mode dition dans un champ de texte, son contenu est effac, le contenu des deux champs nest plus le rsultat dune conversion de lun vers lautre (voir Figure 4.26). Il existe deux possibilits pour viter ce petit problme :
j j

viter que les champs soient effacs en dbut de saisie ; effacer les deux champs lorsque la saisie dbute dans lun des deux.

Votre premier challenge consiste implmenter lune de ces deux solutions :


j

La premire solution ncessite seulement la modication du chier NIB sous Interface Builder. Pour la seconde solution, on utilise : soit la mthode de dlgu (void)textFieldDidBeginEditing:
(UITextField *)textField ;

134

4. Motifs fondamentaux

Figure 4.26 : Effacement du champ en dbut de saisie

soit le mcanisme cible-action avec lvnement Editing Did


Begin.

Risque de plantage
Il ne faut pas modier un champ de texte par programmation pendant son dition par lutilisateur.

Explorer les contrles simples


Nous connaissons les contrles de classe UILabel et UITextField. Nous avons explor les techniques fondamentales de programmation Cocoa Touch : cible-action, dlgation, gestion de la mmoire, KVC et MVC. Vous en savez maintenant suffisamment pour utiliser dautres contrles simples et dvelopper votre propre application.

Autres contrles simples


Les contrles les plus simples sont regroups dans la rubrique Inputs
& Values de la bibliothque dobjets dInterface Builder.

4.4. Challenges

135

Figure 4.27 : Contrles simples de Inputs & Values

On utilise ces contrles de la faon suivante :


j

Label (Label) ; ce contrle statique affiche un texte. Le programme peut modier le texte affich par la proprit text. Barre de progression (Progress View) ; ce contrle statique est une barre de progression. Le programme doit modier la proprit progress (un nombre compris entre 0 et 1) pour visualiser la progression. Indicateur dactivit (Activity Indicator) ; ce contrle statique affiche une roue qui tourne indiquant lutilisateur quune tche est en cours. Le programme met les messages startAnimating et stopAnimating pour dmarrer et arrter le mouvement tournant. La proprit hidesWhenStopped doit prendre pour valeur YES si lon souhaite que lindicateur soit masqu lorsquil nest pas actif. Slecteur (Segmented Control) ; ce contrle est un bouton plusieurs valeurs possibles, lutilisateur slectionne lune de ces valeurs. Le programme utilise la proprit numberOfSegments pour connatre le nombre de choix possibles, et la proprit selectedSegmentIndex pour connatre le choix actuellement slectionn (nombre entier partir de 0). Les cibles-actions doivent tre connectes sur lvnement Value Changed. Bouton (Round Rect Button) ; ce contrle est un bouton simple. Les cibles-actions doivent tre connectes sur lvnement Touch Up Inside. Bascule (Switch) ; ce contrle est un bouton deux tats. Le programme utilise la proprit on pour connatre ltat YES ou NO de la bascule. Les cibles-actions doivent tre connectes sur lvnement Value Changed.

136

4. Motifs fondamentaux

Ascenseur (Slider) ; ce contrle est un ascenseur horizontal ou vertical. Les valeurs min et max sont prcises sous Interface Builder. Le programme utilise la proprit value pour connatre la position de lascenseur. Les cibles-actions doivent tre connectes sur lvnement Value Changed. Champ de Texte (TextField) ; ce contrle est un champ de texte. Nous lavons abondamment expliqu. Cest le contrle le moins facile utiliser de cette liste ; il met plusieurs vnements et il est le seul possder un dlgu. Contrle de pages (Page Control) : ce contrle permet lutilisateur de visualiser le nombre de pages et le numro de la page en cours. Le programme indique le nombre de pages par la proprit numberOfPages, il utilise la proprit currentPage pour connatre le numro ( partir de 0) de la page visualise. La proprit hidesForSinglePage permet de masquer le contrle sil ny a quune page. Les cibles-actions doivent tre connectes sur lvnement Value Changed.

Tous les contrles dynamiques hritent successivement de NSObject, NSResponder, UIView et UIControl. Les contrles statiques nhritent pas de UIControl ; un "contrle statique" est une vue. Le tableau rsume les classes, les proprits, les mthodes et les vnements actifs pour chaque contrle simple.
Tableau 4.2 : Utilisation des contrles simples Nom du contrle Label Progress View Activity Indicator Classe dobjet Proprits Mthodes vnements -

UILabel UIProgress View UIActivity Indicator View

text progress hidesWhen Stopped

start Animating Stop Animating


Value Changed

Segmented Control

UISegmented numberOf Control Segments selectedSegment Index UIButton UISwitch UISlider


-

Round Rect Button Switch Slider

Touch Up Inside Value Changed Value Changed

on value

4.4. Challenges

137

Tableau 4.2 : Utilisation des contrles simples Nom du contrle TextField Classe dobjet Proprits Mthodes Possde un dlgu. vnements Did End On Exit Editing Changed Editing Did Begin Editing Did End Value Changed

UITextField text

Page Control

UIPage Control

numberOfPages currentPage hidesForSingle Page

Crez votre propre application


Limitez-vous des applications sur une seule vue, nous verrons les techniques qui permettent de dvelopper des applications multivues au chapitre suivant. Si vous navez pas dide, vous pouvez essayer dajouter des ascenseurs Convertisseur1. Lutilisateur pourra ainsi effectuer des conversions trs rapidement, sans avoir besoin de saisir un nombre dans un champ de texte. Pour que lapplication soit pratique, il faut que les trois autres contrles changent de valeur, quel que soit le moyen utilis pour indiquer un montant.

Figure 4.28 : Convertisseur1 avec des ascenseurs

Trouver plus dinformations


Les frameworks Cocoa Touch sont trs riches. Nous navons prsent que lutilisation la plus courante des contrles simples. Nous

138

4. Motifs fondamentaux

verrons dautres techniques par la suite mais vous pouvez dores et dj accder des informations plus dtailles dans labondante documentation fournie par Apple sur le site des dveloppeurs (http: //developer.apple.com/).

Figure 4.29 : Site des dveloppeurs dApple

Slectionnez iPhone Dev Center. Saisissez votre identiant et votre mot de passe pour accder aux ressources de dveloppement iPhone ; documentation, exemples, vidos, etc.

Figure 4.30 : Centre de dveloppement iPhone

4.4. Challenges

139

Identifiant Apple
Il est indispensable dtre inscrit comme dveloppeur Apple pour accder aux ressources du centre des dveloppeurs. Vous avez dj un identiant si vous avez tlcharg le SDK iPhone, utilisez le mme. Lobtention dun identiant, le tlchargement du SDK iPhone et laccs aux ressources du centre des dveloppeurs sont gratuits.

4.5. Check-list
Nous connaissions dj le mcanisme Cible-Action. Dans ce chapitre, nous avons continu notre dcouverte des motifs de conception fondamentaux : Dlgation, MVC et KVC. Nous savons crer nos propres classes dobjets. Nous avons maintenant des bases solides pour aborder les techniques plus complexes. Nous avons vu comment structurer les chiers NIB et les contrleurs de vue dune application. Nous avons appris dans quelle partie du code il faut introduire le comportement spcique dsir : dlgu dapplication, dlgus et contrleurs de vue. Plus prcisment, nous avons avanc dans notre connaissance des frameworks Cocoa Touch :
j

Nous connaissons les protocoles de dlgu dapplication et de champ de texte. Nous avons utilis les classes NSCharacterSet et NSScanner. Nous savons localiser les formats de nombre et les chiers NIB. Nous connaissons la chane de rpondeurs et la classe UIResponder. Nous savons utiliser tous les contrles simples de la bibliothque Inputs & Values.

j j j

Concernant le langage Objective C, nous savons maintenant :


j j j j

dnir un protocole, avec les clauses @protocol et @optional ; utiliser la clause @class ; utiliser la mthode respondsToSelector et la fonction SEL ; utiliser le type BOOL et les constantes NSString.

Nous avons dcouvert quelques commandes supplmentaires dans les outils du SDK :

140

4. Motifs fondamentaux

nettoyer les cibles sous XCode aprs avoir supprim ou restructur des ressources ; changer le nom de lapplication sous XCode ; recharger les chiers de classe sous Interface Builder pour prendre en compte les modications effectues sous XCode ; changer la langue et les paramtres rgionaux du simulateur diPhone pour tester nos applications internationales.

j j

4.5. Check-list

141

APPLICATIONS MULTIVUES
Application de type utilitaire ................................................................................ 145 Application Convertisseur2 .................................................................................. 154 Messages dalerte ..................................................................................................... 168 Barre donglets ........................................................................................................... 175 Barres de navigation ................................................................................................ 181 Checklist ........................................................................................................................ 183

143

CHAPITRE 5

Dans ce chapitre, nous crerons une version 2 de notre convertisseur, avant de dlaisser momentanment les dollars et les euros dans les chapitres suivants qui nous porteront vers dautres types dapplications. Notre objectif est de comprendre le fonctionnement gnral des applications multivues : celles dans lesquelles lutilisateur peut changer de vue principale.

5.1. Application de type utilitaire


Le taux de change des devises varie tous les jours midi (le xing). Si notre utilisateur est pointilleux sur les centimes ou sil est trs riche et veut convertir de grosses sommes, il voudra pouvoir modier le taux de conversion utilis par notre convertisseur. Nous allons donc lui proposer cette fonctionnalit.

Figure 5.1 : Application Convertisseur2

Comprendre le fonctionnement dun utilitaire


Crer le projet Convertisseur2
1 Ouvrez XCode et crez un nouveau projet. Nous choisirons le modle Utility Application (Utilitaire). Laissez la case Use Core Data for storage dcoche. Nommez ce projet Convertisseur2.

5.1. Application de type utilitaire

145

Figure 5.2 : Crer un projet de type Utility Application

2 Ajoutez un logo et nommez lapplication ConvertPro. Vous savez comment faire maintenant. Noubliez pas dactiver la case cocher Copy items into destination groups folder (if needed) pour que le logo soit copi dans le dossier du projet. 3 Construisez et lancez lapplication (X+[R]) pour voir ce que cela donne.

Figure 5.3 : Un utilitaire luvre

146

5. Applications multivues

Notre application se comporte comme si la Vue tait double face : j Au recto, un petit bouton est affich en bas droite. Si on le touche, la vue semble se retourner. j Au verso, une barre de titre est affiche en haut, avec un bouton Done qui nous permet de revenir au recto. Examinons le dtail du fonctionnement de ce squelette dapplication.

Structure de base dun utilitaire


Regardons la liste des chiers crs par XCode. Nous avons dabord des classes Objective-C : j MainViewController ; j FlipsideViewController ; j Convertisseur2AppDelegate. Puis les chiers NIB (les autres chiers sont les mmes que pour Convertisseur1) :
j j j

MainWindow.xib ; MainView.xib ; FlipsideView.xib.

Le navigateur de Classes
Sous XCode, la commande Class Browser du menu Project ([Maj]+X+[C]) affiche une fentre qui vous permet de visualiser la hirarchie des classes, la liste des mthodes de chaque classe et leur code source. Vous pouvez ltrer les classes dnies dans le projet ou voir lensemble des classes. On obtient la documentation des classes des frameworks en cliquant sur licne en forme de livre ct du nom de la classe.

Figure 5.4 : Navigateur de classes

5.1. Application de type utilitaire

147

Fonctionnement de base dun utilitaire


Examinez le code source des classes cres par XCode et les chiers NIB sous Interface Builder pour identier les liens. Reprsentons la structure de lapplication obtenue.

Figure 5.5 : Structure dune application de type Utilitaire

Nous reconnaissons une structure dapplication classique : lapplication a un dlgu Convertisseur2AppDelegate qui possde une fentre et un contrleur de vue principal MainViewController. Ce dernier possde son tour un chier NIB MainView.xib. La nouveaut avec ce type dapplication, cest un contrleur FlipsideViewController qui possde un chier NIB FlipsideView.xib. Nous verrons comment cela fonctionne mais auparavant, nous allons nous pencher sur une autre petite diffrence.

Attacher un contrleur un chier NIB


Souvenez-vous comment taient lis le contrleur de vue principal et son chier NIB ; dans le cher NIB MainWindow.xib du dlgu de lapplication (voir Figure 5.6). Dans notre application Convertisseur2, une autre mthode est utilise. Regardez la mthode applicationDidFinishLaunching: du dlgu dapplication, en particulier les lignes qui ne se trouvent pas dans le code du dlgu de lapplication Convertisseur1 :

148

5. Applications multivues

Figure 5.6 : Contrleur de vue dans le chier NIB du dlgu dapplication - (void)applicationDidFinishLaunching: (UIApplication *)application { MainViewController *aController = [[MainViewController alloc] initWithNibName:@"MainView" bundle:nil]; self.mainViewController = aController; [aController release]; mainViewController.view.frame = [UIScreen mainScreen].applicationFrame; [window addSubview:[mainViewController view]]; [window makeKeyAndVisible]; }

La mthode initWithNibName:bundle: permet dinitialiser un contrleur de vue en donnant le nom dun chier NIB (sans lextension .xib ou .nib) et un paquet (Bundle) dans lequel se trouve ce chier NIB. Par dfaut (nil), le chier NIB est recherch dans le paquet de lapplication courante.

Paquet (Bundle)
Un paquet est un dossier contenant du code excutable, des chiers NIB et des ressources diverses.

5.1. Application de type utilitaire

149

Le cadre (frame) de la vue principale (mainViewController.view.frame) est ensuite dni comme tant le cadre ddi lapplication sur lcran ([UIScreen mainScreen].applicationFrame). Par dfaut, une barre dtat est affiche en haut de lcran, la zone restante est ddie lapplication.

Cadre (frame)
Le cadre dune vue est le rectangle dans lequel cette vue est affiche dans la vue ou la fentre qui la contient. Lorigine et la taille du rectangle sont exprimes en pixels relativement au cadre de la vue qui contient.

Cadre ddi lapplication


Lcran a une taille de 480 x 320 pixels sur un iPhone et un iPod Touch, et de 1 024 x 768 pixels sur un iPad. La hauteur de la barre dtat est de 20 pixels. La zone ddie lapplication est la totalit de lcran except la barre dtat. Il est recommand dutiliser la classe UIScreen plutt que dcrire la taille de la vue principale "en dur" dans son code. Cela facilitera ladaptation de votre application sur diffrents appareils, voire de futurs appareils dont la taille de lcran serait diffrente.

Nous venons de voir que lon peut dnir et initialiser un contrleur de vue :
j j

soit dans un chier NIB comme dans Convertisseur1 ; soit par programmation comme dans Convertisseur2.

Cette alternative est toujours vraie : il ny a rien que lon puisse faire dans un chier NIB et que lon ne puisse obtenir par programmation. Les deux mthodes donnent le mme rsultat. Le chier NIB est sans doute plus facile raliser pour le dveloppeur ; quelques clics au lieu de plusieurs lignes de code. La programmation est beaucoup plus souple et plus puissante car elle permet dadapter la vue et son contrleur au contexte en cours, alors que la dnition dans un chier NIB est faite a priori, avant lexcution de lapplication, elle est donc ge.

Animer le changement de vue


Intressons-nous maintenant la faon dont le changement de vue seffectue. Lorsque lutilisateur touche le bouton de la vue principale, le message showInfo est transmis au contrleur de vue.

150

5. Applications multivues

- (IBAction)showInfo { FlipsideViewController *controller = [[FlipsideViewController alloc] initWithNibName:@"FlipsideView" bundle:nil]; controller.delegate = self; controller.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal; [self presentModalViewController:controller animated:YES]; [controller release]; }

Nous connaissons dj la mthode initWithNibName:bundle: qui nous permet ici de crer une instance de FlipsideViewController et de lattacher au chier NIB FlipsideView.xib. Ensuite, linstance de contrleur de la vue principale est dnie comme dlgue du contrleur nouvellement cr. Cela servira pour revenir la vue principale, nous en examinerons le mcanisme plus loin. Le changement de vue est dclench par le message presentModal La proprit modalTransitionStyle dun contrleur de vue permet de spcier le type danimation souhaite. Testez lapplication en utilisant successivement les 4 styles proposs par Apple.
ViewController:animated:.
Tableau 5.1 : Type numr UIModalTransitionStyle Constante Signification Style par dfaut, la vue modale recouvre la vue courante en glissant vers le haut. La vue modale saffiche comme si elle tait au verso de la vue courante. La vue courante se dissout lors de laffichage de la vue modale. La vue courante est "releve" et reste apparente sur un angle de la vue modale. Disponible uniquement partir de la version 3.2.

UIModalTransition StyleCoverVertical UIModalTransition StyleFlipHorizontal UIModalTransition StyleCrossDissolve UIModalTransition StylePartialCurl

Testez galement les diffrents types de boutons proposs dans linspecteur des attributs (X+1) sous Interface Builder.

Figure 5.7 : Diffrents types de bouton sous Interface Builder 151

5.1. Application de type utilitaire

Vue modale
Une vue est dite modale lorsquelle remplace temporairement une autre vue. Cette autre vue sera nouveau prsente lutilisateur lorsque la vue modale disparatra. Une vue modale peut son tour passer le contrle une autre vue modale.

Linstruction [controller release]; mrite une petite explication complmentaire. Il faut respecter la rgle de gestion de la mmoire. Linstance controller de la classe FlipsideViewController vient dtre cre avec +alloc, il faut donc soccuper de sa libration. Mais si on la libre tout de suite la n de la mthode showInfo, ne va-t-elle pas tre dtruite ? La vue Flipside va-t-elle safficher correctement ? En fait, tout va fonctionner correctement car le message presentModal ViewController:animated: retient le paramtre controller dans la proprit modalViewController du contrleur de la vue principale. La libration de linstance controller ne va donc pas provoquer sa destruction immdiate.

Revenir la vue principale


Examinons maintenant comment le contrleur de la vue modale revient la vue principale. Lorsque lutilisateur touche le bouton Done le message done est envoy au propritaire du chier NIB ; vriez la cible-ation du bouton en ouvrant FlipsideView.xib sous InterfaceBuilder. Le contrleur de vue propritaire de ce chier NIB (Flipside
ViewController) dnit la mthode done.
- (IBAction)done { [self.delegate flipsideViewControllerDidFinish:self]; }

Souvenez-vous, le dlgu de FlipsideViewController est le contrleur de la vue principale ; il est affect dans sa mthode showInfo. Regardez le code de la mthode flipsideViewControllerDidFinish: dans le chier MainViewController.m :
- (void)flipsideViewControllerDidFinish: (FlipsideViewController *)controller { [self dismissModalViewControllerAnimated:YES]; }

Lorsque lutilisateur touche le bouton Done pour refermer la vue modale, le contrleur de la vue modale informe le contrleur de la vue principale. Ce dernier doit dsactiver la vue modale puisque cest lui qui la active.
152
5. Applications multivues

Activer une vue modale


Rsumons le principe de gestion des vues modales :
j

La vue modale est dnie dans un chier NIB et attache un contrleur de vue spcique. Lactivation de la vue modale est dclenche par lmission du message presentModalViewController:animated: sur le contrleur de la vue principale. Le retour la vue principale est dclench par lmission du message dismissModalViewControllerAnimated: sur le contrleur de la vue principale.

Utilisation de la dlgation
Vous avez sans doute remarqu le mcanisme de dlgation mis en uvre :
j

Un protocole FlipsideViewControllerDelegate est dni dans la classe FlipsideViewController. Ce protocole dclare la mthode flipsideViewControllerDid Finish: (vriez dans le chier FlipSideViewController.h). Le contrleur de la vue principale MainViewController adopte le protocole FlipsideViewControllerDelegate. Le contrleur de la vue principale se dnit comme dlgu du contrleur de la vue modale la cration de ce dernier. Lorsquil souhaite que la vue modale soit ferme, son contrleur de vue met le message dni dans le protocole vers son dlgu. Lorsque le contrleur de la vue principale reoit ce message, il dsactive la vue modale.

Ce fonctionnement relativement complexe pourrait tre remplac par le code suivant de la mthode done de la classe Flipside ViewController :
- (IBAction)done { [self.parentViewController dismissModalViewControllerAnimated:YES]; }

Le code sans utiliser la dlgation serait donc plus simple. La dlgation est tout de mme une bonne pratique de programmation ; le contrleur de vue principale dclenche la vue modale puis reprend le contrle lorsque lutilisateur souhaite revenir la vue principale. Celui qui dclenche une action en rcupre le rsultat.

5.1. Application de type utilitaire

153

5.2. Application Convertisseur2


Composer la vue principale
Nous souhaitons que la vue principale de lapplication Convertisseur2 soit analogue celle de Convertisseur1. Nous allons donc rcuprer les lments dans le chier NIB. 1 Ouvrez simultanment les deux chiers NIB sous Interface Builder : chier Convertisseur1ViewController.xib du projet Converisseur1 ; chier MainView.xib du projet Convertisseur2. 2 Dans le premier chier, slectionnez les lments rcuprer (utilisez la touche [Maj] pour tendre la slection) : le titre "Convertisseur de Monnaie" ; les labels "Montant en dollars" et "Montant en euros" ; les deux champs de texte. 3 Copiez la slection du premier chier pour la coller dans le second chier. Modiez les couleurs des labels pour amliorer la visibilit. Vous pouvez galement changer la couleur de fond de la vue principale si vous prfrez.

Figure 5.8 : Composition de la vue principale

4 Enregistrez le chier MainView.xib Convertisseur1ViewController.xib.


154
5. Applications multivues

et

fermez

le

chier

Paramtrer le taux de conversion


Composition de la vue modale
1 Ouvrez le chier FlipsideView.xib du projet Convertisseur2 sous Interface Builder pour y ajouter un label et un champ de texte. 2 Modiez le titre de la barre de navigation (en haut de la vue).

Figure 5.9 : Composition de la vue modale

Adapter la classe Convertisseur


Ajoutez les chiers Convertisseur.h et Convertisseur.m du projet Convertisseur1 au projet Convertisseur2. Noubliez pas de copier ces chiers dans le dossier du projet ; nous allons les modier. La classe Convertisseur doit prendre en compte le fait que lutilisateur peut changer le taux de conversion tout moment. La proprit dollarsPourUnEuro est donc modiable durant lexcution de lapplication mais les proprits dollar et euro ne seront plus le rsultat dune conversion de lune vers lautre. Il faudrait recalculer lune des deux valeurs, ou plus simplement les annuler lorsque la proprit dollarsPourUnEuro est modie.

5.2. Application Convertisseur2

155

Ajoutez la mthode setDollarsPourUnEuro: dans le chier Convertisseur.m :


-(void) setDollarsPourUnEuro:(float)newValue { if (dollarsPourUnEuro != newValue) { dollarsPourUnEuro = newValue; self.euro = 0.; } }

Remarquez lemploi de linstruction self.euro=0.;. Elle provoque lmission du message setEuro: qui modie simultanment les proprits euro et dollar. On remet zro les proprits euro et dollar uniquement si le nouveau taux de conversion est diffrent de lancien.

Factoriser le dlgu de champ de texte


Dans lapplication Convertisseur1, le contrleur de la vue principale est aussi le dlgu des champs de texte ; il est charg de vrier que lutilisateur ne saisit que des nombres. Nous avons besoin du mme mcanisme pour vrier que le taux de conversion saisi par lutilisateur est un nombre. Nous allons donc crer un objet spcique pour cette dlgation, plutt que de coner cette mission aux deux contrleurs de vue.

Objet dlgu rutilisable


Il nous faut un objet qui implmente le protocole UITextFieldDelegate et dnisse la mthode textField:shouldChangeCharactersInRange: replacementString:. Dans la classe Convertisseur1ViewController, cette mthode tait utilise pour dnir les valeurs en euros ou en dollars suivant le cas. Notre nouvel objet dlgu devant tre rutilisable dans dautres contextes, il nest pas de sa responsabilit de modier des proprits dautres objets. Appelons cette classe NumericFieldDelegate. Sa responsabilit sera de vrier que le champ de texte contient uniquement des nombres et de retenir ce nombre pour viter que la conversion soit ralise plusieurs fois. 1 Crez les chiers NumericFieldDelegate.h et NumericFieldDelegate.m dans le projet Convertisseur2.

156

5. Applications multivues

2 Dclarez lutilisation du protocole UITextFieldDelegate et la proprit value dans linterface de la classe :


#import <Foundation/Foundation.h> @interface NumericFieldDelegate : NSObject <UITextFieldDelegate> { float value; } @property (nonatomic,assign) float value; @end

3 Modiez le chier NumericFieldDelegate.m :


#import "NumericFieldDelegate.h" @implementation NumericFieldDelegate @synthesize value; - (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string { NSString *resultingString = [textField.text stringByReplacingCharactersInRange:range withString:string]; NSScanner *scan = [NSScanner localizedScannerWithString:resultingString]; [scan scanFloat:&value]; return [scan isAtEnd]; } @end

Le travail de conversion dune chane de caractres en valeur numrique effectu dans la mthode setValueForKey:WithString: de la classe Convertisseur est maintenant ralis par la classe Numeric FieldDelegate. Vous pouvez supprimer cette mthode de la classe Convertisseur, elle ne nous servira plus.

Connecter le dlgu dans le chier NIB


Nous allons effectuer chaque connexion entre un champ de texte et son dlgu dans les chiers NIB. Nous crerons mme les objets dlgus dans les chiers NIB. 1 Ouvrez le chier MainView.xib et faites glisser un objet de type NSObject dans la fentre du chier NIB (attention : pas dans la fentre de la vue principale) (voir Figure 5.10). 2 Slectionnez lobjet nouvellement cr et affichez linspecteur didentit (X+[4]) pour dnir sa classe (NumericFieldDelegate) et son nom (Dollar Field Delegate) (voir Figure 5.11).

5.2. Application Convertisseur2

157

Figure 5.10 : Crer un objet dans MainWindow.xib

Figure 5.11 : Dnition du type dobjet

3 Connectez loutlet delegate du champ de texte destin contenir la valeur en dollars lobjet Dollar Field Delegate. Utilisez linspecteur de connexions (X+[2]) (voir Figure 5.12). 4 Procdez de mme avec les deux autres champs de texte de lapplication :
Euro Field Delegate dans MainView.xib ; Rate Field Delegate dans FlipsideView.xib.

5 Enregistrez les deux chiers NIB.


158
5. Applications multivues

Figure 5.12 : Connexion du champ de texte son dlgu

Finaliser les contrleurs de vue


Contrleur de la vue principale
Dclaration
Dclarez les outlets et les actions dans le chier MainViewController.h :
#import "FlipsideViewController.h" #import "Convertisseur.h" #import "NumericFieldDelegate.h" @interface MainViewController : UIViewController <FlipsideViewControllerDelegate> { IBOutlet UITextField * dollarField; IBOutlet NumericFieldDelegate * dollarFieldDelegate; IBOutlet UITextField * euroField; IBOutlet NumericFieldDelegate * euroFieldDelegate; IBOutlet Convertisseur * convertisseur; } @property (nonatomic,retain) UITextField *dollarField; @property (nonatomic,retain) NumericFieldDelegate *dollarFieldDelegate; @property (nonatomic,retain) UITextField *euroField; @property (nonatomic,retain) NumericFieldDelegate *euroFieldDelegate;

5.2. Application Convertisseur2

159

@property (nonatomic,retain) Convertisseur *convertisseur; - (IBAction) changeValue:(id)sender; - (IBAction) beginEditing:(id)sender; - (IBAction) doneEditing:(id)sender; - (IBAction)showInfo; @end

Nous dclarons la proprit convertisseur comme un outlet. Cela nous permettra dtablir la connexion sous Interface Builder plutt quen modiant le code de la classe MainViewController.

Proprit pour les dlgus


Les dlgus dollarFieldDelegate et euroFieldDelegate sont dj connects aux champs de texte correspondants par leur proprit delegate mais cette proprit est dnie avec lattribut assign au lieu de retain. Pour viter les problmes de gestion de mmoire, il faut que ces dlgus soient dnis comme des proprits avec lattribut retain dans un autre objet ; cest la raison pour laquelle nous les dnissons dans le contrleur de la vue principale.

Dnition
1 Dnissez les accesseurs de proprits et les mthodes spciques dans le chier MainViewController.m :
@implementation MainViewController @synthesize dollarField; @synthesize dollarFieldDelegate; @synthesize euroField; @synthesize euroFieldDelegate; @synthesize convertisseur; - (IBAction) changeValue:sender { if (sender==dollarField) { self.convertisseur.dollar = dollarFieldDelegate.value; euroField.text = [NSString localizedStringWithFormat: @"%.2f",self.convertisseur.euro]; } else { self.convertisseur.euro = euroFieldDelegate.value; dollarField.text = [NSString localizedStringWithFormat: @"%.2f",self.convertisseur.dollar]; } } - (IBAction) beginEditing:(id)sender { if (sender==dollarField) { euroField.text = @""; } else { dollarField.text = @""; }

160

5. Applications multivues

} - (IBAction) doneEditing:(id)sender { [sender resignFirstResponder]; }

2 Librez les outlets du contrleur de vue :


- (void)viewDidUnload { // Release any retained subviews of the main view. // e.g. self.myOutlet = nil; self.dollarField = nil; self.dollarFieldDelegate = nil; self.euroField = nil; self.euroFieldDelegate = nil; self.convertisseur = nil; } - (void)dealloc { [self viewDidUnload]; [super dealloc]; }

Connexions
1 Ouvrez le chier MainView.xib sous Interface Builder. Ajoutez-y un objet que vous dnissez de type Convertisseur. 2 tablissez les connexions du contrleur de la vue principale : champs de texte, dlgus de champ de texte, convertisseur et actions.

Figure 5.13 : Connexions du contrleur de la vue principale

3 Construisez lapplication et testez la vue principale. Vous devez retrouver le comportement de Convertisseur1. Il nous reste faire fonctionner la modication du taux de conversion dans la vue modale.

5.2. Application Convertisseur2

161

Contrleur de la vue modale


Nous allons dnir le contrleur de la vue modale FlipsideViewController selon le mme principe que le contrleur de la vue principale :
j j j

un outlet pour le champ de texte ; un outlet pour le dlgu du champ de texte ; une proprit rate pour communiquer avec le contrleur de la vue principale ; laction doneEditing:.

Laction changeValue: ne sera pas utile pour ce contrleur ; nous navons pas de mise jour faire sur la vue pendant ldition. Laction beginEditing: sera inutile galement.

Dclaration
Effectuez les dclarations dans le chier FlipsideViewController.h :
@protocol FlipsideViewControllerDelegate; #import "NumericFieldDelegate.h" @interface FlipsideViewController : UIViewController { id <FlipsideViewControllerDelegate> delegate; IBOutlet UITextField * rateField; IBOutlet NumericFieldDelegate * rateFieldDelegate; float rate; } @property (nonatomic, assign) id <FlipsideViewControllerDelegate> delegate; @property (nonatomic, retain) UITextField *rateField; @property (nonatomic, retain) NumericFieldDelegate *rateFieldDelegate; @property (nonatomic, assign) float rate; - (IBAction)doneEditing:(id)sender; - (IBAction)done; @end @protocol FlipsideViewControllerDelegate - (void)flipsideViewControllerDidFinish: (FlipsideViewController *)controller; @end

Dnition
1 Modiez le chier FlipsideViewController.m pour dnir les accesseurs et laction :
@synthesize delegate; @synthesize rateField; @synthesize rateFieldDelegate;

162

5. Applications multivues

@synthesize rate; - (IBAction) doneEditing:(id)sender { [sender resignFirstResponder]; }

Nous souhaitons que le champ de texte rateField soit initialis avec la valeur de la proprit rate lorsque la vue saffiche. 2 Modiez la mthode viewDidLoad :
- (void)viewDidLoad { [super viewDidLoad]; rateField.text = [NSString localizedStringWithFormat: @"%.5f",self.rate]; self.view.backgroundColor = [UIColor viewFlipsideBackgroundColor]; }

Inversement, la proprit rate doit prendre la valeur du champ de texte lorsque la vue est referme par lutilisateur. 3 Modiez la mthode done :
- (IBAction)done { if (self.rateFieldDelegate.isModified) self.rate = self.rateFieldDelegate.value; [self.delegate flipsideViewControllerDidFinish:self]; }

Nous avons besoin de savoir si le contenu du champ de texte a t modi par lutilisateur ; si ce nest pas le cas, la proprit value du dlgu du champ de texte est nulle. Il faudra penser dnir une proprit isModified dans notre classe NumericFieldDelegate. 4 Librez les outlets du contrleur de la vue modale :
- (void)viewDidUnload { // Release any retained subviews of the main view. // e.g. self.myOutlet = nil; self.rateField = nil; self.rateFieldDelegate = nil; } - (void)dealloc { [self viewDidLoad]; [super dealloc]; }

5.2. Application Convertisseur2

163

Proprit isModied
1 Ajoutez la proprit modified dans le chier NumericFieldDelegate.h, en spciant quelle est en lecture seule et que son accesseur est isModified :
@interface NumericFieldDelegate : NSObject <UITextFieldDelegate> { float value; BOOL modified; } @property (nonatomic,assign) float value; @property (nonatomic,readonly,getter=isModified) BOOL modified; @end

La proprit doit prendre la valeur NO la cration de chaque instance et la valeur YES chaque modication. 2 Ajoutez une mthode init dans le chier NumericFieldDelegate.m :
- (id) init { if (self == [super init]) { modified = NO ; } return self; }

3 Modiez la mthode textField:shouldChangeCharactersInRange: replacementString: dans le mme chier :


NSString *resultingString = [textField.text stringByReplacingCharactersInRange:range withString:string]; NSScanner *scan = [NSScanner localizedScannerWithString:resultingString]; [scan scanFloat:&value]; modified = YES; return [scan isAtEnd];

Connexions
1 Ouvrez le chier FlipsideView.xib sous Interface Builder. 2 tablissez les connexions du contrleur de la vue modale : champ de texte, dlgus de champ de texte et actions (voir Figure 5.14). 3 Dcochez la case Clear When Editing Begin dans les attributs du champ de texte (X+[1]) an dempcher que le champ de texte ne soit remis zro au dbut de ldition (voir Figure 5.15).

164

5. Applications multivues

Figure 5.14 : Connexions du contrleur de la vue modale

Figure 5.15 : Dcochez la case Clear When Editing Begin

4 Construisez lapplication et testez la vue modale. Elle semble fonctionner mais le taux de conversion saisi par lutilisateur nest pas pris en compte dans la vue principale.

5.2. Application Convertisseur2

165

Communiquer entre les deux contrleurs


Le contrleur de la vue modale tant pilot par le contrleur de la vue principale, il revient logiquement ce dernier dtablir la communication : j La proprit rate doit tre initialise la cration du contrleur de la vue modale. j La valeur de cette proprit doit tre rcupre la fermeture de la vue modale.

Communiquer le taux de conversion


1 Modiez la mthode showInfo dans le chier MainViewController.m pour y initialiser la proprit rate :
- (IBAction)showInfo { FlipsideViewController *controller = [[FlipsideViewController alloc] initWithNibName:@"FlipsideView" bundle:nil]; controller.delegate = self; controller.rate = self.convertisseur.dollarsPourUnEuro; controller.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal; [self presentModalViewController:controller animated:YES]; [controller release]; }

2 Modiez Finish: :

galement

la

mthode

flipsideViewControllerDid

- (void)flipsideViewControllerDidFinish: (FlipsideViewController *)controller { self.convertisseur.dollarsPourUnEuro = controller.rate; [self dismissModalViewControllerAnimated:YES]; }

3 Construisez et testez lapplication Convertisseur2. Son fonctionnement devrait tre satisfaisant.

viter le blocage du clavier


Peut-tre vous tes-vous aperu que parfois, le clavier ne disparat pas lorsque lutilisateur touche le bouton Termin (Done). Ce dfaut se manifeste lorsque le curseur de saisie napparat pas aprs le dernier caractre dans le champ de texte actif.

166

5. Applications multivues

Figure 5.16 : blocage du clavier

On peut demander au champ de texte dadopter le mme comportement quelle que soit la position du curseur. Vous savez dj comment on peut modier le comportement dun champ de texte ; il faut agir sur son dlgu. Ajoutez la mthode textFieldShould Return: dans le chier NumericFieldDelegate.m :
- (BOOL)textFieldShouldReturn:(UITextField *)textField{ return YES; }

Lorsque cette mthode retourne la valeur YES, une pression sur la touche Termin et interprte comme si le curseur tait aprs le dernier caractre. Reconstruisez lapplication et vriez que le dfaut est corrig.

Garder des montants cohrents


Lorsque le taux de conversion est modi, il faudrait effacer le contenu des champs de texte de la vue principale. Actuellement, lutilisateur voit deux montants qui sont le rsultat de la conversion en utilisant lancien taux. Le plus simple est dafficher le contenu de lobjet Convertisseur au retour de la fentre modale ; nous savons que ses proprits sont toujours cohrentes.

5.2. Application Convertisseur2

167

Modier le code
Modiez la mthode flipsideViewControllerDidFinish: dans le chier MainViewController.m :
- (void)flipsideViewControllerDidFinish: (FlipsideViewController *)controller { self.convertisseur.dollarsPourUnEuro = controller.rate; euroField.text = [NSString localizedStringWithFormat: @"%.2f",self.convertisseur.euro]; dollarField.text = [NSString localizedStringWithFormat: @"%.2f",self.convertisseur.dollar]; [self dismissModalViewControllerAnimated:YES]; }

Factoriser
Cest la quatrime fois que nous crivons une instruction contenant [NSString localizedStringWithFormat: @"%.2f",xxx]. Il est temps de mettre en uvre la factorisation ; cela nous permettrait de modier seulement une ligne de code si nous souhaitons modier le format daffichage par exemple. Pour cette factorisation nous avons le choix, soit crire une nouvelle mthode, soit simplement une fonction Objective-C ou encore une macro-instruction. Utilisons cette dernire possibilit. Dnissez une macro stringWithCurrency() au dbut du chier MainViewController.m :
#import "MainViewController.h" #define stringWithCurrency(currency) [NSString localizedStringWithFormat: @"%.2f",currency] @implementation MainViewController

Vous pouvez utiliser cette macro dans les mthodes changeValue: et flipsideViewControllerDidFinish:, par exemple : euroField.text = stringWithCurrency(self.convertisseur.euro);.

Tester
Reconstruisez et testez lapplication pour vrier son comportement. Effectivement les champs dollars et euros prennent la valeur 0.00 lorsque lutilisateur modie le taux de conversion, et uniquement dans ce cas ; leur valeur est inchange si lutilisateur na pas dit le taux de conversion.

5.3. Messages dalerte


Rien ninterdit lutilisateur de Convertisseur2 de saisir un taux de conversion ngatif ou totalement anormal ; 123456,54 par exemple.
168
5. Applications multivues

Pour corriger ce lger dfaut, nous pourrions enrichir la classe NumericFieldDelegate de faon pouvoir en paramtrer le comportement, en xant des bornes min et max, par exemple. Une autre possibilit, celle que nous allons adopter, consiste signaler lutilisateur que le taux de conversion saisi est erron.

Afficher une alerte


Nous souhaitons afficher une alerte si le taux de conversion est erron. Il faut donc dnir une fonction qui en vrie la validit.

Dnir la validit du taux de conversion


Ajoutez une fonction verifyRate dans le chier FlipsideViewController.m ; nous utilisons une fonction C cette fois, pour changer et explorer une autre possibilit :
#import "FlipsideViewController.h" BOOL verifyRate (float rate) { return (rate >= 0.5) && (rate <= 2.); } @implementation FlipsideViewController

Un taux de conversion compris entre 0,5 et 2 est correct. Nous avons cr cette fonction lextrieur de la dnition de la classe FlipsideViewController (avant la clause @implementation). Ainsi nous navons pas besoin de la dclarer dans linterface de la classe. De ce fait, elle est inaccessible pour les autres objets ; nous avons dni une fonction prive la classe FlipsideViewController.

Tester la validit du taux saisi


Nous allons tester la validit du taux saisi par lutilisateur :
j

Lorsque lutilisateur veut revenir la vue principale, il doit rester dans la fentre modale tant que le taux est incorrect. Lorsque lutilisateur touche le bouton Termin pour effacer le clavier ; si le taux est incorrect un message dalerte est affich et le champ de texte doit rester en dition.

Modiez la mthode done dans le chier FlipsideViewController.m :


- (IBAction)done { if ( !(self.rateFieldDelegate.isModified && !verifyRate(self.rateFieldDelegate.value)) ) { if (self.rateFieldDelegate.isModified) self.rate = self.rateFieldDelegate.value;

5.3. Messages dalerte

169

[self.delegate flipsideViewControllerDidFinish:self]; } }

Afficher une fentre dalerte


Modiez la mthode doneEditing: dans le chier FlipsideViewController.m :
- (IBAction) doneEditing:(id)sender { if (self.rateFieldDelegate.isModified && !verifyRate(self.rateFieldDelegate.value)) { UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Taux incorrect" message: @"Le taux de conversion doit tre compris entre 0,5 et 2" delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil]; [alert show]; [alert release]; [sender becomeFirstResponder]; } else { [sender resignFirstResponder]; } }

Remarquez lmission du message becomeFirstResponder sur le champ de texte an quil reste en mode Edition. Nous faisons connaissance ici avec la classe UIAlertView et ses deux mthodes principales :
j

initWithTitle:message:delegate:cancelButtonTitle:otherButton Titles: :

Le titre est une chane de caractres qui sera affiche en haut de la fentre dalerte. Le message est une chane de caractres contenant des informations plus dtailles galement affiches. La possibilit est donne daffecter un dlgu ; ici, cest inutile donc on met la valeur nil. Une chane de caractres contenant le titre du bouton principal. Il est possible aussi dajouter dautres boutons, si besoin on indique ici une liste de chanes spares par une virgule et termine par nil.
j

show qui affiche la fentre au milieu de lalerte. Ensuite, linstance peut tre libre et la fentre sera dtruite ds que lutilisateur aura touch un bouton.

170

5. Applications multivues

Les principales mthodes et proprits de la classe UIAlertView sont rsumes dans le tableau ci-aprs.
Tableau 5.2 : Mthodes et proprits principales de la classe UIAlertView Type Titre Objet Cre une fentre dalerte avec un titre et Mthodes (id) initWithTitle:

(NSString *)title message: en xant le dlgu. La liste des autres (NSString *)message boutons doit se terminer par nil. delegate:(id)delegate cancelButtonTitle:(NSString *)cancelButtonTitle otherButtonTitles: (NSString *)otherButton Titles, ... (NSString *) buttonTitle AtIndex:(NSInteger)button Index (void)show
Proprits @property(nonatomic, Retourne le titre du bouton dont le numro dindice est pass en paramtre. Les indices sont numrots partir de 0. Affiche le rcepteur avec une animation. Retourne le nombre de boutons du rcepteur.

readonly) NSInteger numberOfButtons

@property(nonatomic) Indice du bouton principal. Ou 1 si NSInteger cancelButtonIndex aucun bouton nest dni.

Construisez lapplication et testez-la. Un message dalerte saffiche lorsque vous essayez de sortir du mode ddition du taux de conversion avec une valeur errone.

Figure 5.17 : Message dalerte


5.3. Messages dalerte

171

Feuilles daction
Le fonctionnement que nous avons adopt pour lapplication Convertisseur2 interdit lutilisateur demployer un taux de conversion jug erron. Nous pourrions prfrer un comportement plus souple : signaler que le taux de conversion parat incorrect et laisser lutilisateur choisir de lditer nouveau ou de lutiliser tel quel. Les feuilles daction gres par la classe UIActionSheet permettent dimplmenter ce mcanisme ; une alerte est affiche lcran avec deux boutons ou plus :
j

un bouton dannulation (Cancel Button) permettant lutilisateur dannuler lopration en cours ; un bouton daction (Destructive Button) permettant lutilisateur deffectuer laction.

Remarquez le nom anglais du bouton daction (Destructive). Il voque lutilit des feuilles dactions. Lutilisateur est prvenu que laction peut tre dangereuse. Dailleurs, le bouton daction est rouge par dfaut.

Figure 5.18 : Feuille daction

Les feuilles daction sutilisent de la mme faon que les fentres dalerte. Leur comportement diffre sur les points suivants :
j

Une feuille daction saffiche par-dessus une vue particulire au lieu de safficher au milieu de lcran.

172

5. Applications multivues

j j

Elle est gnralement active par un contrleur de vue, par lmission du message showInView:self.view. Une feuille daction offre un titre mais pas de message dtaill. Par dfaut, une feuille daction propose une alternative lutilisateur, cest--dire deux boutons au lieu dun.

Le tableau ci-aprs rsume les principales mthodes et proprits de la classe UIActionSheet.


Tableau 5.3 : Mthodes et proprits principales de la classe UIActionSheet Type Titre Objet Cre une feuille daction avec un titre en prcisant le dlgu. La feuille prsente un bouton dannulation et un bouton daction. La liste des autres boutons doit se terminer par nil. Mthodes (id) initWithTitle:

(NSString *)title delegate: (id < UIActionSheet Delegate >)delegate cancel ButtonTitle:(NSString *) cancelButtonTitle destructiveButtonTitle: (NSString *)destructive ButtonTitle otherButton Titles:(NSString *)other ButtonTitles, ... (NSString *) buttonTitle AtIndex:(NSInteger)button Index (void)showInView: (UIView *)view

Retourne le titre du bouton dont le numro dindice est pass en paramtre. Les indices sont numrots partir de 0. Affiche le rcepteur avec une animation partir de la vue passe en paramtre. Il est recommand dutiliser une vue racine (vue principale dans une fentre). Nombre de boutons du rcepteur

Proprits @property(nonatomic,

readonly) NSInteger numberOfButtons @property(nonatomic) Indice du bouton dannulation ou 1 sil NSInteger cancelButtonIndex nest pas dni @property(nonatomic) NSInteger destructive ButtonIndex
Indice du bouton daction ou 1 sil nest pas dni

Lutilisateur pouvant toucher lun ou lautre bouton pour sortir de la feuille daction, il faut que lapplication puisse dterminer quel bouton a t touch. Vous avez certainement dj devin le mcanisme mis en uvre : cest encore la dlgation.

5.3. Messages dalerte

173

Dlgu de feuille daction


Le protocole de dlgu pour la classe UIActionSheet est UIActionSheetDelegate. Dans lutilisation la plus courante, le contrleur de vue qui active une feuille daction se dnit comme son dlgu en passant self comme paramtre delegate: lors de linitialisation de la feuille daction. Le dlgu implmente gnralement la mthode actionSheet: clickedButtonAtIndex: de la faon suivante :
- (void)actionSheet:(UIActionSheet *) actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex { if (buttonIndex == [actionSheet cancelButtonIndex]) { // le bouton dannulation a t touch } else if (buttonIndex == [actionSheet destructiveButtonIndex]) { // le bouton daction a t touch } }

Challenge
Modiez lapplication Convertisseur2 en utilisant une feuille daction la place dune fentre dalerte. Ainsi, lutilisateur pourra forcer un taux de conversion qui nous parat anormal.

Dlgu dalerte
De la mme faon que la feuille daction, le protocole UIAlertViewDelegate permet de dnir des dlgus pour les fentres dalerte de la classe UIAlertView. La principale mthode de ce dlgu est alertView:clicked ButtonAtIndex: qui se programme de la mme faon que la mthode quivalente du protocole UIActionSheetDelegate. Dans son comportement par dfaut, une fentre dalerte na pas besoin de dlgu puisquelle ne comporte quun bouton. Mais nous pouvons crer une fentre dalerte avec plusieurs boutons et donc un dlgu. Inversement, il est possible de dnir une feuille daction sans dlgu avec un seul bouton. En fait, les classes UIAlertView et UIActionSheet se programment exactement de la mme faon, seule leur apparence visuelle diffre.

174

5. Applications multivues

5.4. Barre donglets


Nous avons vu comment crer une application de type utilitaire qui prsente une vue principale et une vue secondaire (vue modale) lutilisateur, et les mcanismes pour passer de lune lautre. Si nous voulons produire une application offrant trois vues ou plus, la navigation par vue modale peut ne pas se rvler satisfaisante pour lutilisateur. La navigation par barre donglets est plus adapte ; lutilisateur a toujours la possibilit daccder nimporte quelle vue en touchant longlet correspondant. Les copies dcran montrent notre application Convertisseur2 si elle avait t dveloppe avec une barre donglets.

Figure 5.19 : Convertisseur2 avec une barre donglets

Crer une barre donglet


La barre donglets se situe en bas de lcran, cest un objet de la classe UITabBar qui hrite de la classe UIView.
Figure 5.20 : Barre donglets comprenant 2 lments

5.4. Barre donglets

175

On peut placer de 2 6 lments sur une barre donglets ; il nest pas interdit den mettre plus, mais au-del ils risquent de se chevaucher. Chaque lment est un objet de la classe UITabBarItem affich avec un logo et un titre. Vous pouvez utiliser un des 12 lments pour lesquels le logo et le titre sont prdnis ou crer votre propre logo. Il est galement possible dajouter un badge contenant gnralement une valeur numrique sur un lment de barre donglets, mais on peut y inscrire une chane de caractre quelconque ; il est conseill den limiter la taille deux ou trois caractres.
Figure 5.21 : lments prdnis de barre donglets, dont lun avec un badge

Pour afficher un badge, il suffit daffecter une chane de caractres la proprit badgeValue (de type NSString) de llment de barre donglets. Les autres lments sont dnis dans lun des chiers NIB de lapplication ; nous allons dtailler cela bientt. Pour crer une barre donglets, il suffit sous Interface Builder de faire glisser un contrleur de barre donglets (Tab Bar Controller) dans la fentre du chier NIB.

Figure 5.22 : Contrleur de barre donglets dans la bibliothque dInterface Builder

Une autre possibilit consiste crer une application barre donglets (Tab Bar Application) sous XCode. Dans ce cas, vous pouvez

176

5. Applications multivues

choisir le produit pour lequel lapplication est dvelopp : iPhone (utilisable aussi sur iPod Touch et iPad) ou iPad.

Figure 5.23 : Cration dune application barre donglets

Utiliser un contrleur de barre donglets


Le contrleur de barre donglets, instance de la classe UITabBarController), prend en charge la navigation entre les onglets. Son utilisation ncessite peu deffort de la part du programmeur. Ds que lon ajoute un contrleur de barre donglets un chier NIB, il est associ :
j

une barre donglets ; nous naurons gnralement pas nous en occuper ; une liste de contrleurs de vue (UIViewController) qui contiennent chacun : un lment de barre donglets ; ventuellement une vue, sauf si le contrleur de vue est associ un chier NIB spcique.

5.4. Barre donglets

177

Figure 5.24 : Ajout dun contrleur de barre donglets dans un chier NIB

Les oprations le plus courantes pour dnir une application par onglets sont dcrites ci-aprs.

Ajouter un onglet
Pour ajouter un onglet sous Interface Builder, il suffit dajouter un contrleur de vue dans le contrleur de barre donglets. Un lment de barre donglets sera automatiquement ajout au nouveau contrleur de vue.

Adapter llment de barre donglet


Linspecteur de llment de barre donglets, sous Interface Builder, permet de dnir son icne et son titre.

Figure 5.25 : Liste des lments de barre donglets prdnis

Vous pouvez galement dnir vos propres lments de barre donglets en saisissant son titre et le nom du chier utiliser comme icne. Ce chier doit tre au format PNG et dune taille de

178

5. Applications multivues

30 x 30 pixels. Seule la couche alpha (transparence) de limage sera utilise lors de laffichage.

Dnir la vue de chaque onglet


Chaque onglet dispose de son propre contrleur de vue. Vous savez dj comment utiliser un contrleur de vue :
j

Il faut crer une nouvelle classe qui drive de la classe


UIViewController pour y dnir ses propres outlets et actions.

Il faut associer une vue (UIView) ce contrleur pour y ajouter les contrles de linterface utilisateur ; boutons, champs de texte, etc. Cette vue peut tre associe. soit en faisant glisser un objet View dans le contrleur de vue ; soit en donnant le nom du chier NIB qui dcrit la Vue, dans linspecteur du contrleur de vue sous Interface Builder.

Pour nir, il faut tablir les connexions entre les contrles dnis dans la vue et les outlets et actions du contrleur de vue.

Les contrleurs de vue associs un contrleur de barre donglets ne drogent pas ce mode opratoire. Quun contrleur de vue appartienne un contrleur de barre donglets est presque transparent pour lutilisateur. La proprit tabBarItem (de type UITabBarItem) contient llment de barre donglets associ au contrleur de vue. Elle est dnie dans la classe UIViewController et donc disponible dans toutes les classes drives, par exemple pour y afficher un badge.

Figure 5.26 : Exemple de chier NIB contenant les vues pour tous les onglets

5.4. Barre donglets

179

Modier la navigation par onglets


Insrer un contrleur de vue dans un contrleur de barre donglets suffit pour le fonctionnement de la navigation entre les diffrents onglets. Il nest pas ncessaire de driver la classe UITabBar Controller, elle est utilise telle quelle. Si besoin, on peut en modier le comportement en utilisant le dlgu de la classe UITabBarController. Il doit adopter le protocole UITabBarControllerDelegate dont les mthodes principales sont donnes dans le tableau.
Tableau 5.4 : Principales mthodes du protocole UITabBarControllerDelegate Signature de la mthode Objet de la mthode Demande au dlgu si le contrleur de vue peut tre activ.

(BOOL) tabBarController: (UITabBarController *) tabBarController should SelectViewController:(UIView Controller *)viewController (void) tabBarController: (UITabBarController *)tabBar Controller didSelectView Controller:(UIViewController *) viewController

Informe le dlgu quun contrleur vient dtre slectionn. Ce peut tre le mme que celui qui est dj slectionn.

Par exemple, dans une application Convertisseur2 base sur une barre donglets, nous pourrions utiliser la mthode tabBar Controller:shouldSelectViewController: an de mettre jour laffichage des champs de texte de la vue principale, lorsque lutilisateur a modi le taux de conversion.
- (void) tabBarController:(UITabBarController *) tabBarController didSelectViewController: (UIViewController *)viewController { if (viewController==self) { dollarField.text = stringWithCurrency(self.convertisseur.dollar); euroField.text = stringWithCurrency(self.convertisseur.euro); } }

Challenge
Inspirez-vous des lments contenus dans cette section pour rcrire lapplication Convertisseur2 avec une barre donglets plutt quavec une fentre modale. Le code de cette nouvelle version est plus simple ; les mthodes permettant dactiver et deffacer la vue modale ne sont plus ncessaires.
180
5. Applications multivues

5.5. Barres de navigation


Les barres de navigation (Navigation Bar) sont principalement utilises pour parcourir une structure hirarchique de donnes. Lapplication Contacts en est un exemple : j La vue racine (Root View) contient la liste des groupes. j Lorsquon slectionne un groupe, on accde une vue contenant la liste des contacts de ce groupe. j Lorsquon slectionne un contact, on affiche une vue contenant les informations dtailles de ce contact. j Chacune de ces vues contient une barre de navigation, en haut de lcran, contenant le titre de la vue. j La barre de navigation de toutes les vues, sauf celle de la vue racine, offre un bouton de retour (Back Button) qui permet de revenir la vue prcdente ; la vue prcdente et le bouton de retour ont le mme titre. j La barre de navigation peut offrir un bouton supplmentaire droite.

Figure 5.27 : Navigation dans lapplication Contacts

Spcificit iPhone/iPod Touch


Lapplication avec barre de navigation est spcique liPhone et liPod Touch du fait de leur cran de taille rduite. Lquivalent sur iPad est lapplication vue fractionne (Split View) dtaille dans le chapitre qui dcrit les spcicits de cet appareil.

5.5. Barres de navigation

181

Crer une barre de navigation


linstar de la barre donglets, pour crer une barre de navigation sous Interface Buider, il faut faire glisser un contrleur de navigation(Navigation Controller) dans la fentre du chier NIB. Le contrleur de navigation, instance de la classe UINavigation Controller), prend en charge la navigation entre les vues. Son utilisation ncessite peu deffort de la part du programmeur. Ds que lon ajoute un contrleur de navigation un chier NIB, il est associ :
j

une barre de navigation ; nous naurons gnralement pas nous en occuper ; une contrleur de vue racine (UIViewController) qui contient un lment de navigation.

Figure 5.28 : Contrleur de navigation dans un chier NIB

la diffrence dun contrleur de barre donglets, qui contient tous les contrleurs de vue accessibles lutilisateur, le contrleur de navigation contient seulement le contrleur de la vue racine. Les autres vues devront tre ajoutes par programmation.

Utiliser une barre de navigation


La navigation par barre de navigation est adapte pour prsenter des vues contenant des informations de plus en plus dtailles. partir dune vue, on peut soit ajouter une vue contenant une information plus dtaille, soit revenir la vue prcdente qui contient des informations moins dtailles.

182

5. Applications multivues

On parle de pile de navigation pour dsigner tous les contrleurs de vues grs par le contrleur de navigation, ceux qui doivent tre conservs car lutilisateur doit pouvoir y revenir.

Pile
Une pile est une collection dans laquelle seul le dernier objet ajout est accessible. On empile un objet pour lajouter la collection, on le dpile pour len retirer. Une pile dobjets fonctionne comme une pile dassiettes.

La pile est initialise avec le contrleur de vue racine. Pour changer de vue, il faut empiler un contrleur de vue dans la pile de navigation, en envoyant un message pushViewController:animated: au contrleur de navigation. Nous verrons un exemple de mise en uvre au chapitre suivant. Lorsquun contrleur de vue est empil, la vue associe est affiche avec une barre de navigation et un bouton de retour. Lorsque lutilisateur touche le bouton de retour, le contrleur de vue est dpil et le contrleur de vue suivant dans la pile est affich.

5.6. Checklist
Nous avons vu dans ce chapitre les principaux types dapplications multivues :
j j

utilitaire, avec une vue principale et une vue modale ; application barre donglets, avec le contrleur de barre donglets
UITabBarController ;

application barre de navigation et le contrleur de navigation


UINavigationController.

Nous avons dtaill le fonctionnement des vues modales et du contrleur de barre donglets et ralis une version 2 de notre convertisseur permettant lutilisateur de modier le taux de conversion. Nous mettrons en application le principe de fonctionnement du contrleur de navigation aux chapitres suivants : nous crerons une application pour naviguer dans une structure de donnes. Nous avons galement examin le fonctionnement des alertes (UIAlertView) et des feuilles daction (UIActionSheet).

5.6. Checklist

183

CONTRLES COMPLEXES
Utiliser un slectionneur ........................................................................................ 187 Utiliser les conteneurs Cocoa .............................................................................. 205 Utiliser les Vues en table ........................................................................................ 208 Checklist ........................................................................................................................ 228

185

CHAPITRE 6

Dans ce chapitre, nous allons examiner le fonctionnement des contrles visuels qui dpendent dun ensemble de donnes :
j j

vues en table, qui permettent de prsenter une liste de donnes ; slectionneurs, qui permettent lutilisateur de slectionner une valeur.

Nous en proterons pour apprendre manipuler des dates ainsi que les conteneurs utiliss en Objective-C : tableaux et dictionnaires. Nous utiliserons ces lments pour dbuter lapplication Emprunts1, un aide-mmoire pour nous souvenir des objets que nous avons prts nos amis, ce qui nous permettra aussi de mettre en uvre les barres de navigation.

6.1. Utiliser un slectionneur


Un slectionneur (picker) est un contrle visuel en forme de tambour ; lutilisateur le fait tourner pour choisir une valeur.

Figure 6.1 : Exemples de slectionneurs

Slectionneur de date
Nous allons commencer par une mise en pratique du cas le plus simple : le slectionneur de date (date picker).

Figure 6.2 : Mise en uvre du slectionneur de date

6.1. Utiliser un slectionneur

187

Exemple de mise en uvre


Crez un nouveau projet de type View-based Application sous XCode. Appelez-le Picker1.

Cration de linterface
Ouvrez le chier Picker1ViewController.xib et composez linterface utilisateur avec :
j j j

un Label ; deux boutons dont vous changez le titre : Lire et Aujourdhui ; un slectionneur de date.

Figure 6.3 : Composition de linterface

Cration du contrleur de vue


1 Modiez le chier Picker1ViewController.h :
#import <UIKit/UIKit.h> @interface Picker1ViewController : UIViewController { IBOutlet UILabel * label; IBOutlet UIDatePicker * datePicker ; } @property (nonatomic,assign) UILabel * label; @property (nonatomic,assign) UIDatePicker * datePicker; -(IBAction) readPicker ; -(IBAction) setPicker ; @end

2 tablissez les connexions sous Interface Builder. Laction readPicker doit tre connecte lvnement Touch Up Inside du bouton

188

6. Contrles complexes

Lire. Laction setPicker doit tre connecte lvnement Touch Up Inside du bouton Aujourdhui.

3 Ouvrez le chier Picker1ViewController.m, modiez la mthode viewDidUnload et ajoutez les mthodes readPicker et setPicker :
@synthesize label; @synthesize datePicker; - (IBAction) readPicker { label.text = [[datePicker date] description]; } - (IBAction) setPicker { [datePicker setDate:[NSDate date] animated:YES] ; } - (void)viewDidUnload { // Release any retained subviews of the main view. // e.g. self.myOutlet = nil; self.label = nil; self datePicker = nil; }

4 Construisez lapplication et testez-la sur le simulateur. Nous dtaillerons bientt les classes UIDatePicker et NSDate utilises dans cette application. Nous avons employ par ailleurs une mthode description. Cette mthode est dnie dans la classe NSObject ; elle est donc disponible dans toutes les classes et retourne une chane de caractres qui dcrit le rcepteur.

Dcrivez vos instances


Pensez dnir la mthode description dans les classes que vous dnissez, vous pourrez ainsi utiliser le descripteur %@ pour inclure vos instances dans une chane de caractres.

La classe UIDatePicker
Testez lapplication Picker1 en essayant plusieurs congurations de paramtres sous Interface Builder.

Figure 6.4 : Paramtres dun slectionneur de date


6.1. Utiliser un slectionneur

189

Le paramtre mode permet de modier la prsentation visuelle du slectionneur en fonction de lusage que lon veut en faire. Un slectionneur de date est un objet de la classe UIDatePicker. Ses diffrents paramtres peuvent tre dnis sous Interface Builder ou par programmation laide des proprits des instances de la classe.
Tableau 6.1 : Prsentations visuelles du slectionneur de date Prsentation Mode sous Interface Builder Date&Time Time Date Timer Proprit datePickerMode

UIDatePickerModeDate AndTime UIDatePickerModeTime UIDatePickerModeDate UIDatePickerModeCount DownTimer

Tableau 6.2 : Principales proprits de la classe UIDatePicker Thme Date et calendrier Proprit Objet de la proprit Date affiche ou 0 si le slectionneur est en mode Timer. Mode daffichage du slectionneur.

@property(nonatomic, retain) NSDate *date @property(nonatomic) Mode UIDatePickerMode datePickerMode Attributs temporels @property(nonatomic, retain) NSDate *maximumDate @property(nonatomic, retain) NSDate *minimumDate @property(nonatomic) NSInteger minuteInterval @property(nonatomic) NSTimeInterval countDownDuration

Date maximale affiche ou nil sil ny a pas de maximum. Date minimale affiche ou nil sil ny a pas de minimum. Intervalle minimum affich, en minutes. Doit tre un diviseur de 60. Valeur minimum 1 (par dfaut) et valeur maximum 30. Dure affiche comprise entre 0 et 23h59, ou 0 lorsque le slectionneur nest pas en mode Timer.

La classe UIDatePicker dnit galement une mthode setDate: animated: qui permet de changer la date affiche avec une animation. Pour changer la valeur affiche, on peut aussi modier la proprit
date. Dans ce cas, il ny a pas danimation. Essayez ces deux procds dans la mthode setPicker de lapplication Picker1.

190

6. Contrles complexes

Vous pouvez galement connecter laction datePicker du contrleur de vue Picker1ViewController lvnement Value Changed du slectionneur de date ; le texte du label voluera ds que lutilisateur changera la valeur affiche.

NSTimeInterval
La proprit countDownDuration de la classe UIDatePicker est de type NSTimeInterval, quivalent au type double. Il reprsente un intervalle de temps exprim en secondes.

Gestion des dates


La gestion des dates est un rel d sur un appareil destin tre utilis dans le monde entier, qui doit donc prendre en compte les diffrentes faons de reprsenter les dates et les diffrents calendriers. Le systme mis en place par Apple permet de simplier la tche des dveloppeurs qui souhaitent la plus large diffusion de leurs applications. Elle pourra vous paratre un peu complexe si vos ambitions sont plus limites. Le mot date dsigne simplement un instant prcis mesur partir dune rfrence absolue. Un calendrier est une structuration du temps en jour-mois-anne. Un instant donn est toujours reprsent par la mme date, indpendante de la localisation, alors que le calendrier dpend de la culture et du lieu gographique. Outre le calendrier grgorien utilis en occident, iPhone OS propose les calendriers hbreu, islamique, chinois, bouddhiste et japonais. Pour exprimer un instant en jour-mois-anne, il faut la combinaison dun instant (la date) et dun calendrier. On obtient alors les composants dune date (le jour, le mois et lanne) dans un calendrier donn. Concentrons-nous sur les classes les plus utilises : j NSDate qui reprsente une date ; j NSDateFormatter qui permet deffectuer les conversions entre chane de caractres et date.

NS et UI
Le nom de chaque classe commence par deux caractres majuscules qui identient le framework dans lequel la classe est dnie. Par exemple UI pour UIKit et NS pour NextStep. Ce systme est un anctre de Mac OS X. Les classes NS que nous utilisons sont communes aux environnements iPhone OS et Mac OS X. Le framework UIKit est disponible uniquement dans lenvironnement iPhone OS.

6.1. Utiliser un slectionneur

191

La classe NSDate
Les dates, ou instants particuliers, sont reprsentes par des instances de la classe NSDate dont les principales mthodes sont rsumes dans le tableau. Elles permettent de raliser larithmtique de base sur les dates :
j j j

comparer deux dates ; calculer la dure espaant deux dates ; dnir une nouvelle date en ajoutant une dure une date.

Bien entendu, les dures peuvent tre positives ou ngatives. Elles sont du type NSTimeInterval qui nest rien dautre quun double exprimant une dure en secondes.
Tableau 6.3 : Principales mthodes de la classe NSDate Thme Mthode Objet de la mthode Mthode de classe qui retourne une instance initialise linstant prsent Initialise le rcepteur linstant prsent. Mthode de classe qui retourne une instance initialise un nombre donn de secondes partir de linstant prsent Initialise le rcepteur un nombre donn de secondes partir de linstant prsent. Retourne la date la plus prcoce entre le rcepteur et la date donne en paramtre. Retourne la date la plus tardive entre le rcepteur et la date donne en paramtre. Compare le rcepteur la date donne en paramtre. Retourne NSOrderedSame lorsque les dates sont identiques, NSOrderedDescending lorsque le rcepteur est plus tardif que la date donne en paramtre, et NSOrderedAscending si elle est plus prcoce. Retourne la dure entre le rcepteur et la date passe en paramtre. Retourne la dure entre le rcepteur et linstant prsent. Cre une nouvelle date initialise un nombre donn de secondes partir du rcepteur. Cration + (id)date et initialisation

(id)init + (id) dateWithTime IntervalSinceNow: (NSTimeInterval)seconds (id) initWithTime IntervalSinceNow: (NSTimeInterval)seconds Comparaisons (NSDate *) earlier Date:(NSDate *) anotherDate (NSDate *) laterDate: (NSDate *)anotherDate (NSComparisonResult) compare:(NSDate *) anotherDate

Obtenir des dures

Ajouter une dure

(NSTimeInterval) timeIntervalSinceDate: (NSDate *)anotherDate (NSTimeInterval) timeIntervalSinceNow (id) addTimeInterval: (NSTimeInterval)seconds

192

6. Contrles complexes

La classe NSDateFormatter
La classe NSDateFormatter permet de convertir une chane de caractres en une date et vice-versa. Chaque instance de cette classe contient un calendrier, un fuseau horaire et une localisation qui sont par dfaut ceux rgls dans lappareil. Le format de conversion doit tre spci par la mthode setDateFormat:. On utilise ensuite lune des deux mthodes dateFromString: et stringFromDate: pour effectuer les conversions. 1 Modiez la mthode readPicker de la classe Picker1ViewController dans lapplication Picker1 :
- (IBAction) readPicker { formatter = [[NSDateFormatter alloc] init]; [formatter setDateFormat:@"EEEE dd MMMM HH:mm"]; label.text=[formatter stringFromDate:[datePicker date]]; [formatter release]; }

2 Testez lapplication sur le simulateur diPhone. Changez la localisation (Rglages->Gnral->International->Format rgional) et vriez que le texte affich et le slectionneur de date rpercutent la localisation par dfaut de lappareil.

Figure 6.5 : Picker1 sous diffrentes localisations

6.1. Utiliser un slectionneur

193

Tableau 6.4 : Principales mthodes de la classe NSDateFormatter Thme Initialisation Mthode Objet de la mthode Initialise le rcepteur avec les paramtres par dfaut de lappareil (calendrier, fuseau horaire, localisation). Convertit une chane de caractres en date. Convertit une date en chane de caractres. Dnit le format de conversion selon le standard technique n35 de lUnicode. Dnit la reprsentation des jours de la semaine utiliser. Le premier lment de tableau est le dimanche. Dnit la reprsentation des mois de lanne utiliser.

(id) init (NSDate *) date FromString: (NSString *)string (NSString *) stringFromDate: (NSDate *)date

Conversion

Formats

(void) setDate Format:(NSString *) string Symbols:(NSArray *) array (void) setMonth Symbols:(NSArray *) array

Gestion des symboles (void) setWeekday

Vous pouvez consulter le standard technique n35 de lUnicode sur le site de lorganisation (http://unicode.org/reports/tr35/tr35-6.html#Date_Format_ Patterns) pour connatre toutes les possibilits de formatage des dates. Un format de date est une chane de caractres contenant des codes qui reprsentent les diffrentes composantes dune date.
Tableau 6.5 : Codes de formatage de date les plus courants Code Reprsente Exemple pour le 12/12/2010 15:30 Les 2 derniers chiffres de lanne Le mois numrique Le jour dans le mois Lheure (de 0 23) Les minutes

yy MM dd HH mm

10 2010 12 dcembre 12 samedi 15 30

yyyy Lanne MMMM Le mois littral EEEE Le jour dans la semaine littral

En utilisant un slectionneur UIDatePicker et un formateur NSDateFormatter, le dveloppeur a lassurance que les dates seront toujours affiches en employant le rglage rgional dcid par lutilisateur de lappareil.

194

6. Contrles complexes

Challenge
Les utilisateurs pointilleux auront remarqu que les langues rgionales (provenal, breton, occitan) ne sont pas disponibles sur liPhone. Heureusement, la classe NSDateFormatter est pleine de ressources. Les mthodes setWeekdaySymbols: et setMonthSymbols: permettent de dnir la reprsentation des jours de la semaine et des mois de lanne. Votre objectif est dafficher la date en breton dans le label de lapplication Picker1.

Figure 6.6 : Affichage de la date en breton

Vous pourrez utiliser un formateur de date qui pourrait tre initialis dans la mthode viewDidLoad du contrleur de vue :
- (void)viewDidLoad { [super viewDidLoad]; formatter = [[NSDateFormatter alloc] init]; NSArray * mois = [NSArray arrayWithObjects:@"Genver", @"Chwevrer",@"Meurzh",@"Ebrel",@"Mae", @"Mezheven",@"Gouere",@"Eost", @"Gwengolo",@"Here",@"Du",@"Kerzu",nil]; NSArray * jours = [NSArray arrayWithObjects:@"Sul", @"Lun",@"Meurzh",@"Mercher",@"Yaou", @"Gwener",@"Sadorn",nil]; [formatter setMonthSymbols:mois]; [formatter setWeekdaySymbols:jours];

6.1. Utiliser un slectionneur

195

[formatter setDateFormat:@"EEEE d MMMM HH:mm"]; }

Slectionneur standard
Un slectionneur standard ressemble visuellement un slectionneur de date mais il fonctionne diffremment. Nous allons commencer par un exemple simple pour dcouvrir la classe UIPickerView.

Application Picker2
Lapplication Picker2 va simplement prsenter un slectionneur lutilisateur, pour lui permettre de choisir un pays. Le pays choisi sera affich dans un label.

Figure 6.7 : Application Picker2

Crez un nouveau projet de type View-based Application sous XCode et appelez-le Picker2.

Cration de linterface
Ouvrez le chier Picker2ViewController.xib et composez linterface utilisateur avec :
j j

un Label ; un slectionneur standard (Picker View).

196

6. Contrles complexes

Interface du contrleur de vue


1 Modiez le chier Picker2ViewController.h :
#import <UIKit/UIKit.h> @interface Picker2ViewController : UIViewController <UIPickerViewDelegate,UIPickerViewDataSource>{ IBOutlet UILabel * label; NSArray * valeurs; } @property (nonatomic,assign) UILabel * label; @end

2 Remarquez les diffrences avec le contrleur de vue de Picker1 : Il ny a pas doutlet sur le slectionneur. Nous avons besoin dun tableau de valeurs. Le contrleur adopte les protocoles UIPickerViewDelegate et UIPickerViewDataSource. Le slectionneur standard ncessite un dlgu pour fonctionner. Deux protocoles sont dnis et donc on pourrait mme dire quil lui faut deux dlgus. En pratique, ces deux protocoles seront gnralement adopts par un seul contrleur de Vue. Cest donc le slectionneur qui connat le contrleur de vue, son dlgu, et ce dernier na donc gnralement pas besoin de connatre le slectionneur ; il ny a pas doutlet sur le slectionneur. Nous avons besoin dun tableau de valeur dans le contrleur de vue car cest lui, en tant que dlgu du slectionneur, qui doit grer les valeurs afficher ; nous allons expliquer cela.

Connexions
tablissez les connexions sous Interface Builder :
j

Loutlet label du contrleur de vue doit tre connect au champ Label de linterface. Les outlets delegate et dataSource du slectionneur doivent tre connects au contrleur de vue (Files owner).

Figure 6.8 : Connexions du contrleur de vue Picker2ViewController

6.1. Utiliser un slectionneur

197

Code du contrleur
1 Ouvrez le chier Picker2ViewController.m, modiez la mthode viewDidUnload et viewDidLoad puis ajoutez les mthodes dnies dans les protocoles :
@synthesize label; - (NSInteger)numberOfComponentsInPickerView: (UIPickerView *)pickerView{ return 1; } - (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component{ return [valeurs count]; } - (NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component{ return [valeurs objectAtIndex:row]; } - (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component{ self.label.text = [valeurs objectAtIndex:row]; } // Implement viewDidLoad to do additional setup after loading the view, typically from a nib. - (void)viewDidLoad { [super viewDidLoad]; valeurs = [[NSArray alloc] initWithObjects:@"France", @"Allemagne",@"Italie",@"Espagne",@"Portugal",nil]; self.label.text = [valeurs objectAtIndex:0]; } - (void)viewDidUnload { // Release any retained subviews of the main view. // e.g. self.myOutlet = nil; self.label = nil; [valeurs release]; }

2 Construisez lapplication et testez-la sur le simulateur. Nous avons construit un tableau valeurs initialis avec une liste de pays. Au moment o il saffiche, le slectionneur demande un certain nombre dinformations son dlgu ; elles seront puises dans ce tableau :
j j

Combien y a-t-il de lignes au total ? Que dois-je afficher sur telle ou telle ligne ?

Le slectionneur va galement envoyer un message son dlgu chaque fois que lutilisateur le manipulera.
198
6. Contrles complexes

Nous dtaillerons tout cela. Auparavant, tudions la classe UIPickerView.

Classe UIPickerView
Un slectionneur est un objet qui permet dafficher un ou plusieurs tambours. Chaque tambour contient une liste de valeurs ; lutilisateur choisit lune de ces valeurs en le faisant tourner. Les tambours sont les composants (components) du slectionneur, chaque composant contient plusieurs lignes ou ranges (rows).

Figure 6.9 : Slectionneur deux composants

Les dveloppeurs ont une tendance naturelle crire du code qui dcide ce qui doit tre affich lcran. La programmation Cocoa est diffrente, on parle de contrle invers :
j

Les contrleurs envoient des instructions simples aux vues : O doivent-elles safficher ? Quelles sont leurs proprits ?

Les vues prennent en charge toute la partie visuelle : affichage et animation. Les vues sous-traitent les activits qui ne relvent pas strictement du comportement visuel leur dlgu.

6.1. Utiliser un slectionneur

199

Les slectionneurs UIPickerView savent safficher et faire tourner les tambours sous limpulsion de lutilisateur mais ils ne connaissent pas leur contenu. Pour savoir ce quils doivent afficher, ils consultent leur dlgu et leur source de donnes (voir section suivante).
Tableau 6.6 : Principales mthodes de la classe UIPickerView Thme Recharger les donnes Mthode Objet de la mthode Notie au rcepteur que les valeurs du composant ont t modies. leurs de tous les composants ont t modies. Slection

(void) reloadComponent: (NSInteger)component

(void) reloadAllComponents Notie au rcepteur que les va-

(void) selectRow: Slectionne une ligne pour un (NSInteger)row inComponent: composant, ventuellement avec (NSInteger)component une animation visuelle. animated:(BOOL)animated (NSInteger) selectedRowIn Retourne la ligne slectionne Component:(NSInteger) pour un composant du component slectionneur.

Un contrle qui nen est pas un


Contrairement au slectionneur de date, le slectionneur standard nest pas un contrle. La classe UIPickerView ne drive pas de la classe UIControl. On ne peut donc pas utiliser le mcanisme cible-action avec un slectionneur standard. Cest le dlgu qui est noti des changements dtats.

Source de donnes
Un slectionneur standard ncessite deux dlgus :
j

delegate qui joue le rle de dlgu traditionnel : contrle des

vues, positionnement, rponse aux actions, il doit rpondre au protocole <UIPickerViewDelegate> ;


j

dataSource, source de donnes, qui fournit des informations relatives aux valeurs afficher et rpond au protocole <UIPicker ViewDataSource>.

Dans lapplication Picker2, le contrleur de vue est la fois, comme souvent, le dlgu et la source de donnes du slectionneur. Nous y avons donc dni :

200

6. Contrles complexes

la mthode numberOfComponentsInPickerView: qui retourne 1 ; nous informons le slectionneur quil doit afficher un seul composant (un seul tambour) ; la mthode pickerView:numberOfRowsInComponent: qui retourne [valeurs count] pour informer le slectionneur que le composant doit comporter autant de lignes que dlments dans le tableau
valeurs ; tableau qui contient la liste des pays afficher ;

la mthode pickerView:titleForRow:forComponent: qui retourne la chane de caractres afficher sur la range row : [valeurs objectAtIndex:row] ; la mthode pickerView:didSelectRow:inComponent: qui est appele lorsque lutilisateur vient de manipuler lun des tambours.

Ces mthodes admettent un paramtre pickerView, ce qui permet un mme dlgu et une mme source de donnes de grer plusieurs slectionneurs.

Tableau 6.7 : Mthodes du protocole UIPickerViewDataSource Mthode Objet de la mthode Doit retourner le nombre de composants du slectionneur pass en paramtre. Doit retourner le nombre de lignes pour le composant et le slectionneur passs en paramtres.

(NSInteger) numberOfComponents InPickerView:(UIPickerView *) pickerView (NSInteger) pickerView: (UIPickerView *)pickerView numberOfRowsInComponent: (NSInteger)component

Tableau 6.8 : Mthodes du protocole UIPickerViewDelegate Thme Dimensions de la vue Mthode Objet de la mthode Doit retourner la hauteur en pixels dans laquelle doit safficher une ligne pour le composant et le slectionneur passs en paramtres. Doit retourner la largeur en pixels dans laquelle doit safficher une ligne pour le composant et le slectionneur passs en paramtres.

(CGFloat) pickerView: (UIPickerView *)picker View rowHeightFor Component:(NSInteger) component (CGFloat) pickerView: (UIPickerView *)picker View widthForComponent: (NSInteger)component

6.1. Utiliser un slectionneur

201

Tableau 6.8 : Mthodes du protocole UIPickerViewDelegate Thme Mthode Objet de la mthode Contenu de la vue (NSString *) picker Retourne une chane de caractUne de ces mthodes View:(UIPickerView *) res afficher sur la ligne du compickerView titleForRow: posant du slectionneur passs est obligatoire (NSInteger)row for en paramtres.

Component:(NSInteger) component (UIView *) pickerView: Retourne une Vue afficher sur la (UIPickerView *)picker ligne du composant du slectionView viewForRow: neur pass en paramtres. La vue (NSInteger)row for passe en paramtre peut tre Component:(NSInteger) rutilise. component reusingView: (UIView *)view
Slection dune ligne

(void) pickerView: (UIPickerView *)picker View didSelectRow: (NSInteger)row inComponent: (NSInteger)component

Lutilisateur vient de slectionner la ligne du composant du slectionneur pass en paramtres.

Adapter le slectionneur au contexte


Les protocoles UIPickerViewDelegate et UIPickerViewDataSource permettent une grande diversit dutilisation des slectionneurs.

Figure 6.10 : Slectionneur deux composants

Dans le slectionneur reprsent ici, le composant gauche contient une liste de pays et le composant droit une liste de villes. Il est souhaitable que la liste des villes change lorsque lutilisateur change de pays.
202
6. Contrles complexes

Structure de donnes
Les donnes que nous devons manipuler ont une structure plus complexe que celles que nous avons manipules jusquici. Nous avons besoin : j dun tableau contenant la liste des pays ; j pour chaque pays, dun tableau contenant la liste des villes de ce pays. En programmation Cocoa, lorsquon veut tablir une mise en correspondance de deux listes dobjets ici une liste de pays et une liste de listes de villes , on utilise un dictionnaire de la classe NSDictionary. Le bon endroit pour initialiser cette structure de donnes est la mthode viewDidLoad du contrleur de vue :
- (void)viewDidLoad { [super viewDidLoad]; pays = [[NSArray alloc] initWithObjects:@"France", @"Allemagne",@"Italie",@"Espagne",@"Portugal",nil]; villes = [[NSDictionary alloc] initWithObjects: [NSArray arrayWithObjects: [NSArray arrayWithObjects:@"Paris", @"Marseille",@"Lyon",@"Toulouse", @"Bordeaux",nil], [NSArray arrayWithObjects:@"Berlin", @"Hambourg",@"Munich", @"Stuttgart",nil], [NSArray arrayWithObjects:@"Rome", @"Florence",@"Naples",@"Venise", @"Milan",nil], [NSArray arrayWithObjects:@"Madrid", @"Barcelone",@"Sville",nil], [NSArray arrayWithObjects:@"Lisbonne", @"Porto",nil],nil] forKeys:pays]; self.paysChoisi = @"France"; self.label.text = [[villes objectForKey:self.paysChoisi] objectAtIndex:0]; }

Les classes et mthodes utilises seront expliques plus loin dans ce chapitre.

Source de donnes
Nous devons crire les 2 mthodes du protocole UIPickerView DataSource qui retournent le nombre de composants et le nombre de lignes pour chaque composant du slectionneur. Nous voulons afficher deux composants :
- (NSInteger)numberOfComponentsInPickerView: (UIPickerView *)pickerView{ return 2; }

6.1. Utiliser un slectionneur

203

Le nombre de lignes est xe pour le premier composant, cest le nombre de pays. Il dpend du pays choisi pour le deuxime composant, il faudra donc penser ajouter une proprit paysChoisi dans notre contrleur de vue :
- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component{ if (component == 0) { return [pays count]; } else { return [[villes objectForKey:self.paysChoisi] count]; } }

Dlgu
Dans le premier composant, le titre afficher en fonction du numro de ligne est le nom du pays. Dans le second composant, il faut afficher le nom de la ville et nous devons ici aussi prendre en compte le pays choisi.
- (NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component{ if (component == 0) { return [pays objectAtIndex:row]; } else { return [[villes objectForKey:self.paysChoisi] objectAtIndex:row]; } }

Lorsque lutilisateur change de pays (lorsquil touche le composant numro 0), il faut :
j j

modier la proprit paysChoisi du contrleur de vue ; indiquer au slectionneur que la liste des villes afficher nest plus la mme.
- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component{ if (component == 0) { self.paysChoisi = [pays objectAtIndex:row]; self.label.text = self.paysChoisi; [pickerView reloadComponent:1]; } else { self.label.text = [[villes objectForKey:self.paysChoisi] objectAtIndex:row]; } }

204

6. Contrles complexes

Remarquez linstruction [pickerView reloadComponent:1]; qui indique au slectionneur quil doit modier le contenu du composant numro 1 (la liste des villes).

Challenge
Vous avez maintenant tous les lments pour raliser lapplication Picker3 qui prsente un slectionneur deux tambours, un pour les pays et un pour les villes, et qui affiche dans le label la dernire slection de lutilisateur. Bien sr, la liste des villes dpend du pays slectionn. Si vous souhaitez comprendre plus prcisment le fonctionnement des tableaux et des dictionnaires, reportez-vous la section suivante avant de raliser lapplication Picker3.

6.2. Utiliser les conteneurs Cocoa


Les conteneurs sont des structures de donnes de base, indispensables pour raliser des applications au modle de donnes complexe. Dans ce chapitre, nous dcrivons : j les tableaux, qui sont des instances de la classe NSArray ; j les dictionnaires, qui sont des instances de la classe NSDictionary. Ces structures de donnes sont particulirement intgres au langage Objective-C ; on peut les parcourir avec linstruction for in :
NSString * pays; NSArray * toutLesPays=[NSArray arrayWithObjects:@"France", @"Allemagne",@"Italie",@"Espagne",@"Portugal",nil]; for ( pays in toutLesPays ) { // la boucle est excute avec les lments du tableau }

Tableaux NSArray
Un tableau est une liste ordonne de pointeurs vers dautres objets, indexe par un entier compris entre 0 et n-1 si le tableau contient n objets. Les diffrents objets peuvent tre de classes diffrentes mais toutes les positions de 0 n-1 doivent tre occupes ; il est interdit davoir un pointeur nil au milieu du tableau.

Objet nul
On ne peut pas insrer nil dans un conteneur mais on peut utiliser lobjet nul [NSNull null]. Lobjet nul ne rpond aucune mthode except celles de NSObject dont il drive.

6.2. Utiliser les conteneurs Cocoa

205

Les mthodes principales de la classe NSArray sont rsumes dans le tableau. Les mthodes les plus utilises sont objectAtIndex: qui retourne lobjet associ lindice pass en paramtre, et count qui retourne le nombre dlments dans le tableau.
Tableau 6.9 : Principales mthodes de la classe NSArray Thme Crer un tableau Mthode Objet de la mthode Cre un tableau constitu de la liste des objets passs en paramtre. Les lments de la liste sont spars par une virgule. Le dernier lment de la liste doit tre nil. Initialise un tableau constitu de la liste des objets passs en paramtre. Les lments de la liste sont spars par une virgule. Le dernier lment de la liste doit tre nil. Retourne YES si anObject est dans le tableau, NO sinon. Les lments du tableau sont compars anObject par la mthode -isEqual: dclare dans NSObject. Retourne le nombre dlments du tableau. Retourne le dernier lment du tableau. Retourne llment dont lindice est pass en paramtre. index doit tre compris entre 0 et count1. Retourne lindice de llment gal anObject. Les lments du tableau sont compars anObject par la mthode -isEqual:. Si plusieurs lments sont gaux anObject, lindice le plus petit est retourn. Si aucun lment nest gal anObject, la mthode retourne NSNotFound. Retourne lindice de llment gal anObject. Les lments du tableau sont compars anObject par la mthode -isEqual:. Si plusieurs lments sont gaux anObject, lindice le plus petit est retourn. Si aucun lment nest gal anObject, la mthode retourne NSNotFound. La recherche est limite aux indices compris dans lintervalle range.

+ (id) arrayWithObjects: (id)firstObj, ...

Initialiser un (id) initWithObjects: (id)firstObj, ... tableau

Interroger un tableau

(BOOL) containsObject: (id)anObject

(NSUInteger)count (id)lastObject (id) objectAtIndex: (NSUInteger)index


Trouver un objet

(NSUInteger) index OfObject:(id)anObject

(NSUInteger) index OfObject:(id)anObject inRange:(NSRange)range

206

6. Contrles complexes

Pour crer un intervalle de type NSRange, on peut employer la fonction utilitaire NSMakeRange, par exemple :
NSRange range = NSMakeRange(4, 8);

Dictionnaires NSDictionary
Un tableau permet de retrouver un objet par son indice qui est obligatoirement un entier. Il est parfois intressant dutiliser des indices quelconques, une chane de caractres par exemple. Cest le rle dun dictionnaire. Un dictionnaire est une liste dentres. Chaque entre est constitue :
j j

dune cl, un objet quelconque, souvent de la classe NSString ; dune valeur associe la cl, galement un objet quelconque.

Aucune entre ne doit prsenter de cl ou de valeur nil (lobjet nul est autoris). Une cl doit tre unique dans le dictionnaire. Les mthodes principales de la classe NSDictionary sont rsumes dans le tableau. Les mthodes les plus utilises sont objectForKey: qui retourne la valeur associe la cl passe en paramtre et count qui retourne le nombre dlments dans le dictionnaire.
Tableau 6.10 : Principales mthodes de la classe NSDictionary Thme Crer un dictionnaire Mthode Objet de la mthode Cre un dictionnaire constitu des objets contenus dans le tableau objects avec les cls contenus dans le tableau keys. Les deux tableaux doivent contenir le mme nombre dlments.

+ (id) dictionaryWith Objects:(NSArray *) objects forKeys: (NSArray *)keys

Initialiser un diction- (id) initWithObjects: Initialise un dictionnaire constitu (NSArray *)objects des objets contenus dans le tableau naire forKeys:(NSArray *)keys objects avec les cls contenus dans le tableau keys. Les deux tableaux doivent contenir le mme nombre dlments. Accder aux cls et (NSUInteger)count aux valeurs Retourne le nombre de paires (cl, objet) du dictionnaire. Retourne lobjet associ la cl aKey, ou nil si la cl nest pas dans le dictionnaire. Retourne un tableau constitu de lensemble des cls du dictionnaire, ou un tableau vide si le dictionnaire est vide.

(id) objectForKey: (id)aKey (NSArray *)allKeys

6.2. Utiliser les conteneurs Cocoa

207

Conteneurs mutables
Les objets des classes NSArray et NSDictionary sont immuables ; une fois crs, on ne peut les modier. Il existe des versions modiables (mutable) de ces classes qui, en pratique, sont peu utilises. La classe NSMutableArray drive de NSArray. Elle dnit en particulier les mthodes supplmentaires suivantes : j addObject: qui permet dajouter un lment la n du tableau ; j insertObject:atIndex: qui permet dinsrer un lment dans le tableau ; j removeObjectAtIndex: pour supprimer un lment connaissant son indice ; j replaceObjectAtIndex:withObject: pour remplacer un des lments du tableau. Les mthodes les plus utilises de la classe NSMutableDictionary sont : j setObject:forKey: qui permet dajouter une entre dans le dictionnaire ; j removeObjectForKey: pour supprimer une entre connaissant sa cl.

6.3. Utiliser les Vues en table


La vue en table (TableView) est le principal outil de navigation au sein dune structure de donnes arborescente. Vous avez maintenant les connaissances suffisantes pour en comprendre le fonctionnement et pour la mettre en uvre dans vos applications : j pattern Modle-Vue-Contrleur ; j dlgation ; j source de donnes ; j conteneurs. Pour illustrer le fonctionnement densemble des classes mises en jeu, nous crerons lapplication Emprunts1. Il sagit dun aidemmoire pour nous souvenir des objets que nous avons prts nos amis. qui les avons-nous prts et quelle date ?

Prsentation gnrale
Avec les vues en table, lutilisateur visualise une liste de donnes puis il choisit un lment de cette liste pour visualiser une autre liste lie cet lment, etc. Il parcourt ainsi la structure de donnes, visualise les informations dtailles ou dite les donnes.

208

6. Contrles complexes

Lexemple typique de ce mode de navigation est lapplication Contacts :


j j

Lapplication prsente une liste de groupes. Lutilisateur choisit un groupe ; il visualise alors la liste des contacts appartenant ce groupe. Il parcourt la liste des contacts du groupe. Lorsquil en choisit un, il en visualise les informations dtailles quil peut diter sil le souhaite.

Figure 6.11 : Liste des groupes de contacts

Figure 6.12 : Liste des contacts

6.3. Utiliser les Vues en table

209

Figure 6.13 : Informations dtailles dun contact

Chacune de ces vues est une vue en table de style diffrent :


j j j

vue en table simple ; vue en table indexe (par les lettres de lalphabet) ; vue en table par groupe (tlphones, adresses de courriel, adresses postales, etc.).

Le fonctionnement de lapplication Emprunts1 est analogue celui de Contacts :


j

Le sommet de la structure de donnes est la liste des catgories dobjet (CD, DVD, Livre). Lorsquune catgorie et choisie, lutilisateur accde la liste des objets de cette catgorie. Il peut ajouter un objet ou diter les informations pour un objet.

Figure 6.14 : Application Emprunts1

Paradoxalement, nous utiliserons peu les objets de la classe UITableView pour la programmation des vues en table. Nous manipulerons surtout les protocoles et classes associs :

210

6. Contrles complexes

j j

la classe UITableView, bien sr ; la classe UITableViewController, que nous driverons et qui rpond aux protocoles :
<UITableViewDelegate> ; <UITableViewDataSource>.

la classe UITableViewCell, qui est la vue devant tre affiche dans une cellule ou ligne de la table ; la classe NSIndexPath dont les instances permettent de reprer une cellule particulire de la table.

La classe UITableViewCell mritera une attention particulire car elle permet toute la richesse daffichage de la vue en table. La programmation dune vue en table consiste principalement dnir un contrleur de vue qui hrite de UITableViewController. Cette classe prend en charge, en particulier, la prsentation gnrale de la table et le dlement vertical lorsque la liste ne tient pas entirement sur lcran.

Crer une vue en table


Pour crer une vue en table, il suffit de crer et dinitialiser un contrleur de vue qui hrite de la classe UITableViewController. Par programmation, linitialisation du contrleur de vue cre automatiquement la vue en table :
j

pour crer une vue en table simple :


init ; initWithStyle:UITableViewStylePlain.

pour crer une vue en table par groupe :


initWithStyle:UITableViewStyleGrouped.

Sous Interface Builder, il faut faire glisser un objet de type Table View Controller dans la fentre du document NIB. Le contrleur de vue ainsi ajout contient une instance de la classe UITableView. Sous XCode, lorsquon cre une application de type Navigationbased, une barre de navigation et un contrleur de vue en table sont automatiquement crs. La vue en table associe au contrleur est accessible par sa proprit tableView dnie dans la classe UITableViewController.

6.3. Utiliser les Vues en table

211

1 Ouvrez XCode et crez une application de type Navigation-based. 2 Laissez la case Use Core Data for storage dcoche et nommez lapplication Emprunts1.

Afficher la table
Prparer la structure de donnes
La classe RootViewController est le contrleur de vue racine, elle drive de UITableViewController. Cest cette classe que nous allons modier pour apporter le comportement souhait notre application. Nous commencerons par crer le tableau des catgories afficher sur la premire table. 1 Ajoutez une proprit categories dans linterface de la classe RootViewController :
@interface RootViewController : UITableViewController { NSArray * categories; } @property(nonatomic,retain) NSArray * categories; @end

2 Modiez la mthode viewDidLoad dans le chier RootViewController.m pour initialiser le tableau des catgories :
@synthesize categories; - (void)viewDidLoad { [super viewDidLoad]; self.categories = [NSArray arrayWithObjects: @"CD", @"DVD",@"Livres",@"Divers",nil]; }

3 Enlevez les marques de commentaires autour de la mthode viewDidLoad.

Dimensionner la table
linstar du slectionneur standard, la vue en table interroge sa source de donnes pour dimensionner son affichage. Si la table est de style group, la mthode numberOfSections InTableView: doit tre implmente dans le contrleur de vue et retourner le nombre de sections. La table des catgories de lapplication Emprunts1 ntant pas dcompose en section, vriez que cette mthode retourne 1.

212

6. Contrles complexes

La mthode tableView:numberOfRowsInSection: est obligatoire. Modiez-la pour retourner le nombre de lignes dans la table (le nombre de catgories) :
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return [self.categories count]; }

Afficher les titres


Le titre inscrit dans la barre de navigation est, par dfaut, le titre du contrleur de vue actif. Modiez la mthode viewDidLoad pour indiquer le titre Catgories.
- (void)viewDidLoad { [super viewDidLoad]; self.categories = [NSArray arrayWithObjects: @"CD", @"DVD",@"Livres",@"Divers",nil]; self.title = @"Catgories"; }

Si la table est cre en mode Group et si lon souhaite donner un titre chaque section, il faut que le contrleur de vue implmente la mthode tableView:titleForHeaderInSection: qui retourne une instance de NSString.

Dlgu et Source de donnes


Dans un but de simplication, nous crivons quun contrleur de vue en table doit implmenter telle ou telle mthode sans prciser si cette mthode est dnie dans le protocole de dlgu ou dans celui de source de donne de la vue en table.

Dcrire une ligne


La mthode retenue par Apple pour afficher une ligne de la table rpond plusieurs problmatiques :
j

Il faut pouvoir reprer la ligne en question, lui donner une identication. Il ne faut pas brider le dveloppeur dans sa crativit. Il faut que la programmation daffichages simples reste simple. La mmoire est limite et il faut tenir compte du fait que seules quelques lignes sont rellement affiches lcran un instant donn.

j j j

6.3. Utiliser les Vues en table

213

Reprer la ligne
Une ligne dans une table est repre par une instance de la classe NSIndexPath. Cette classe fournit deux proprits section et row qui permettent didentier une ligne (row) dans une section de la table (section). Avec une table ne contenant quune section, seule la proprit row est utilise. La section et la ligne dans la section sont numrotes partir de 0. (La premire section a le numro 0.)

NSIndexPath
Les proprits section et row sont dnies dans une extension de la classe NSIndexPath qui la rend plus facile utiliser avec les vues en table.

Cellules de table
Chaque ligne de la table est affiche dans une vue de type UITableViewCell, appele cellule (cell). Cette classe dnit un comportement par dfaut qui facilite la programmation dans les cas simples. Elle peut aussi tre drive ou peut inclure dautres vues ou dautres contrles an dobtenir un comportement enrichi. Cest le contrleur de vue de la table qui est charg de fabriquer les cellules pour chaque ligne la demande de la vue en table. Le contrleur doit implmenter la mthode tableView:cellForRow AtIndexPath: et retourner la cellule initialise qui doit tre affiche sur la ligne repre par le paramtre indexPath. Nous allons avancer dans la comprhension des cellules avant de voir un exemple pratique de mise en uvre.

Recycler les cellules


mesure que lutilisateur parcourt la liste de la vue en table, de nouvelles lignes sont affiches et dautres disparaissent de lcran. Nous venons de voir que lorsquune ligne est sur le point dapparatre lcran, la vue en table demande son contrleur de crer une cellule et de linitialiser. Mais que se passe-t-il lorsquune ligne disparat de lcran ? La mmoire tant limite, on ne peut se permettre de toutes les conserver, mais ce serait dommage de toutes les dtruire. Si une ligne disparat, cest quune autre apparat lcran et quil faudra crer une cellule pour cette nouvelle ligne. Cela prend du temps de

214

6. Contrles complexes

crer une cellule et il faut aussi conomiser la batterie. Lide est donc de recycler les cellules qui disparaissent de lcran. Les instances de UITableView entretiennent cet effet une liste de cellules rutilisables. On peut obtenir une cellule en appelant la mthode dequeueReusableCellWithIdentifier:. Cette mthode retourne nil sil ny a pas de cellule rutilisable. Lidentiant pass en paramtre est une chane de caractres. Si la vue en table contient des cellules de diffrents types, il est important de reprer chaque type par un identiant spcique. Lidentiant dune cellule est dni lors de sa cration, laide de la mthode initWithStyle:reuseIdentifier: de la classe UITableView Cell. Cest une bonne pratique de toujours vrier sil nexiste pas une cellule rutilisable avant den crer une nouvelle du mme type. Examinez la mthode tableView:cellForRowAtIndexPath: de la classe RootViewController. Le recyclage des cellules y est dj prvu, le dveloppeur na plus qu saisir le code pour congurer la cellule :
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { static NSString *CellIdentifier = @"Cell"; UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; if (cell == nil) { cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease]; } // Configure the cell. return cell; }

Classe UITableViewCell
La mthode dinitialisation de la classe UITableViewCell prend un paramtre identifier qui permet de dnir lidentiant de la cellule pour sa rutilisation, et un paramtre style qui dnit son style de prsentation lcran. Les styles les plus utiliss sont :
j

UITableViewCellStyleDefault, style par dfaut, une ligne de texte avec une image optionnelle ; UITableViewCellStyleSubtitle, style avec sous-titre, deux lignes de texte et une image optionnelle.

6.3. Utiliser les Vues en table

215

Figure 6.15 : Style par dfaut sans image

Figure 6.16 : Style par dfaut avec image

Figure 6.17 : Style avec sous-titre et image

Ces diffrents lments de la cellule sont accessibles par les proprits de la classe UITableViewCell :
j

textLabel, proprit de type UILabel * qui contient le texte principal de la cellule ; detailTextLabel, proprit de type UILabel * qui contient le texte secondaire de la cellule (seulement si la cellule est de style avec sous-titre) ; imageView, proprit de type UIImageView * qui contient limage affiche gauche de la cellule.

216

6. Contrles complexes

Il est galement possible dagrmenter chaque cellule dun accessoire qui saffiche sur la droite. Il sagit dune icne qui indique lutilisateur les oprations quil peut raliser. Le type daccessoire afficher est indiqu avec la proprit accessoryType de la classe UITableViewCell. Les valeurs autorises pour cette proprit sont prcises dans le tableau.
Tableau 6.11 : Valeurs autorises pour la proprit accessoryType Icne Valeur de la proprit Utilisation

UITableViewCellAccessory Indique quune touche sur la ligne permet dacDisclosureIndicator cder des informations plus dtailles. UITableViewCellAccessory Indique quune touche sur laccessoire permet DetailDisclosureButton daccder des informations plus dtailles. UITableViewCellAccessory Indique que la ligne est slectionne. Checkmark UITableViewCellAccessory Indique que la ligne nest pas slectionne et ne None contient pas daccessoire spcique.

Nous voulons afficher les catgories dobjets et que lutilisateur accde la liste des objets de cette catgorie lorsquil touche la ligne correspondante. 1 Modiez la mthode -tableView:cellForRowAtIndexPath: du chier RootViewController.m.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { static NSString *CellIdentifier = @"Cell"; UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; if (cell == nil) { cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease]; } cell.textLabel.text = [categories objectAtIndex:indexPath.row]; cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator; return cell; }

2 Construisez lapplication et testez-la. Laffichage est correct mais il faut maintenant que lapplication ragisse lorsque lutilisateur touche une catgorie.

6.3. Utiliser les Vues en table

217

Ragir une slection


Prparer la structure de donnes
Comme nous lavons fait lors de notre tude des slectionneurs, avec les pays et les villes, nous allons reprsenter les listes dobjets prts dans un dictionnaire index par la catgorie dobjet. Au dpart, les listes dobjets sont vides. 1 Ajoutez une proprit lendObjects dans linterface de la classe RootViewController :
@interface RootViewController : UITableViewController { NSArray * categories; NSDictionary * lendObjects; } @property(nonatomic,retain) NSArray * categories; @property(nonatomic,retain) NSDictionary * lendObjects; @end

2 Modiez la mthode viewDidLoad dans le chier RootViewController.m pour initialiser le dictionnaire des objets prts. Nous employons ici des tableaux modiables de la classe NSMutableArray car lutilisateur doit pouvoir modier les listes dobjets :
@synthesize categories,lendObjects; - (void)viewDidLoad { [super viewDidLoad]; self.title = @"Catgories"; self.categories = [NSArray arrayWithObjects:@"CD",@"DVD",@"Livres",@"Divers",nil]; self.lendObjects = [NSDictionary dictionaryWithObjects: [NSArray arrayWithObjects:[NSMutableArray array], [NSMutableArray array],[NSMutableArray array], [NSMutableArray array],nil] forKeys:self.categories]; }

Afficher la liste dtaille


Lorsque lutilisateur touche une cellule de la vue en table, le contrleur de vue reoit un message tableView:didSelectRowAtIndexPath:. Modiez cette mthode pour y crer un nouveau contrleur de vue et lafficher lcran. Ce contrleur de vue doit connatre la liste dobjets afficher, il aura donc aussi une proprit lendObjects :
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { ObjectListViewController * objectListViewController = [[ObjectListViewController alloc]

218

6. Contrles complexes

initWithStyle:UITableViewStylePlain]; NSString * category = [self.categories objectAtIndex:indexPath.row]; objectListViewController.title = category; objectListViewController.lendObjects = [self.lendObjects objectForKey:category]; [self.navigationController pushViewController: objectListViewController animated:YES]; [objectListViewController release]; }

Si laccessoire ajout dans les cellules avait t du type UITableViewCellAccessoryDetailDisclosureButton, ce code aurait du tre plac dans la mthode tableView:accessoryButtonTappedForRow WithIndexPath:. Cette mthode est appele lorsque laccessoire est un bouton et quil est touch par lutilisateur. Il faut maintenant crer la classe ObjectListViewController. Crez une nouvelle classe sous XCode (X+N), choisissez un contrleur de vue qui drive de UITableViewController.

Figure 6.18 : Cration dun contrleur drivant de UITableViewController

6.3. Utiliser les Vues en table

219

1 Ajoutez la proprit lendObjects dans linterface de la classe :


@interface ObjectListViewController : UITableViewController{ NSMutableArray * lendObjects; } @property(nonatomic,retain) NSMutableArray * lendObjects; @end

2 Modiez le chier ObjectListViewController.m an de prendre en compte cette proprit pour laffichage de la table. Laissez inchanges les autres mthodes du chier.
@synthesize lendObjects; - (void)viewDidUnload { self.lendObjects = nil; } - (NSInteger)numberOfSectionsInTableView: (UITableView *)tableView { return 1; } - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return [lendObjects count]; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { static NSString *CellIdentifier = @"Cell"; UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; if (cell == nil) { cell = [[[UITableViewCell alloc] initWithStyle: UITableViewCellStyleDefault reuseIdentifier: CellIdentifier] autorelease]; } cell.textLabel.text = [[lendObjects objectAtIndex:indexPath.row] description]; return cell; }

3 Ajoutez limportation de linterface de la classe ObjectList ViewController dans le chier RootViewController.m :


#import " ObjectListViewController.h"

4 Reconstruisez lapplication et testez-la (voir Figure 6.19). Les listes sont vides, ce qui tait prvu, et un bouton de retour est automatiquement ajout par le contrleur de navigation. Vous pouvez dj naviguer dans la structure de donnes. Il ne nous reste plus qu doter notre application dune fonction pour ajouter des objets dans les listes.

220

6. Contrles complexes

Figure 6.19 : La liste des objets prts est vide

Ajouter un lment
Classe LendObject
Nous avons besoin dune classe pour reprsenter un objet prt et ses proprits :
j j j

le nom de lobjet ; le nom de lemprunteur ; la date du prt.

Cette classe est seulement un rceptacle de donnes, elle ne contient pas dautre mthode que les accesseurs de ses proprits. 1 Sous XCode, crez une nouvelle classe LendObject qui drive de NSObject. Dclarez les proprits dans le chier LendObject.h :
@interface LendObject : NSObject { NSString * objectName; NSString * borrowerName; NSDate * lendDate; } @property(nonatomic,retain) NSString * objectName; @property(nonatomic,retain) NSString * borrowerName; @property(nonatomic,retain) NSDate * lendDate; @end

6.3. Utiliser les Vues en table

221

2 Modiez le chier LendObject.m pour y dnir les accesseurs de proprits et la mthode dealloc.
@implementation LendObject @synthesize objectName, borrowerName, lendDate; - (void)dealloc { self.objectName = nil; self.borrowerName = nil; self.lendDate = nil; [super dealloc]; } @end

Contrleur de vue LendObjecViewController


Il nous faut maintenant une Vue et un contrleur de vue pour diter les proprits dune instance de la classe LendObject. Sous XCode, crez une nouvelle classe qui drive de UIViewController, dcochez la case UITableViewController subclass et cochez la case With XIB for user interface. Nous aurons besoin en effet dun chier NIB pour dcrire linterface utilisateur.

Figure 6.20 : Cration de la classe LendObjectViewController

222

6. Contrles complexes

Dclaration de linterface
1 Intitulez le chier LendObjectViewController.m puis ouvrez le chier LendObjectViewController.h pour dclarer les outlets et les proprits. 2 Dclarez une action doneEditing: qui nous servira pour effacer le clavier.
#import <UIKit/UIKit.h> #import "LendObject.h" @interface LendObjectViewController : UIViewController { LendObject * lendObject; IBOutlet UITextField * objectNameField; IBOutlet UITextField * borrowerNameField; IBOutlet UIDatePicker * datePicker; } @property(nonatomic,retain) LendObject * lendObject; @property(nonatomic,retain) UITextField * objectNameField; @property(nonatomic,retain) UITextField *borrowerNameField; @property(nonatomic,retain) UIDatePicker * datePicker; - (IBAction) doneEditing:(id)sender; @end

Dnition des mthodes


1 Ouvrez le chier LendObjectViewController.m pour dnir les accesseurs des outlets et proprits. Modiez la mthode view DidUnload pour librer les outlets et les proprits. 2 Crez laction doneEditing: pour effacer le clavier comme nous lavons fait prcdemment et crez la mthode viewWill Disappear:. Cette dernire mthode est dnie dans la classe UIViewController, elle est appele lorsque la vue va disparatre de lcran ; cest le bon endroit pour prendre en compte la saisie effectue par lutilisateur.
@synthesize lendObject, objectNameField, borrowerNameField, datePicker; - (void)viewDidUnload { self.lendObject = nil; self.objectNameField = nil; self.borrowerNameField = nil; self.datePicker = nil; } - (void)viewWillDisappear:(BOOL)animated{ self.lendObject.objectName = self.objectNameField.text; self.lendObject.borrowerName=self.borrowerNameField.text; self.lendObject.lendDate = self.datePicker.date; [super viewWillDisappear:animated]; }

6.3. Utiliser les Vues en table

223

- (IBAction) doneEditing:(id)sender { [sender resignFirstResponder]; }

Le retour vers lcran prcdent sera pris en charge par le contrleur de navigation ; nous navons pas besoin de nous en occuper ici.

Cration du chier NIB


Ouvrez le chier LendObjectViewController.xib. Disposez les contrles pour btir linterface utilisateur de saisie dun prt.

Figure 6.21 : Interface de saisie pour le prt dun objet

tablissez les connexions avec les outlets et laction du contrleur de vue. Vous pouvez en proter pour retoucher quelques paramtres des contrles pour la saisie :
j j j

augmenter la taille de caractre des champs de texte ; donner la valeur Done la cl Return des champs de texte ; rgler le slectionneur de date en mode Date.

Nous avons termin linterface utilisateur pour la saisie des nouveaux prts. Il nous reste programmer la fonction pour accder cette saisie depuis la liste des objets prts (toujours vide, pour linstant).

224

6. Contrles complexes

Activer la fonction dajout


Lactivation de la fonction dajout ncessite deux lments :
j j

un bouton pour permettre lutilisateur de lactionner ; une action connecte sur ce bouton pour activer linterface utilisateur de saisie.

Ajoutez une action dans le chier ObjectListViewController.h :


- (IBAction) addItem;

La barre de navigation de linterface utilisateur est actuellement occupe :


j j

gauche par le bouton de retour ; au centre par le titre de lcran.

Il nous reste une place droite pour le bouton dajout. Les boutons de la barre de navigation sont de la classe UIBarButtonItem, ils peuvent comporter une image et un titre. Une vingtaine de boutons sont prdnis dans Cocoa Touch que vous pouvez visualiser sous Interface Builder. Nous utiliserons le bouton dajout standard reprsent par le signe plus.

Bouton dajout
Ajoutez une mthode viewDidAppear: dans le chier ObjectListViewController.m pour y crer un bouton de barre de navigation et lajouter droite. Le bouton est connect laction addItem lors de sa cration. La mthode viewDidAppear: est dnie dans la classe UIViewController, elle est appele lorsque la vue vient de safficher lcran.
- (void)viewDidAppear:(BOOL)animated { [super viewDidAppear:animated]; UIBarButtonItem * addButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:self action:@selector(addItem)]; self.navigationItem.rightBarButtonItem = addButton; [addButton release]; }

Action addItem
Nous allons maintenant dnir laction addItem toujours dans le chier ObjectListViewController.m. Il nous faut :
j

crer un contrleur de vue de la classe LendObjectViewController, celle que nous venons de coder pour soccuper de la saisie ; charger le chier NIB correspondant cette classe ;

6.3. Utiliser les Vues en table

225

j j j

crer un nouvel objet de la classe LendObjet ; ajouter ce nouvel objet la liste des objets prts ; transmettre ce nouvel objet au contrleur de vue pour quil en effectue la saisie ; afficher la vue pour la saisie.
#import "LendObjectViewController.h"

1 Dclarez la classe que nous allons utiliser en tte du chier : 2 Crez la mthode addItem :
- (void)addItem{ LendObjectViewController * itemViewController = [[LendObjectViewController alloc] initWithNibName: @"LendObjectViewController" bundle:nil]; LendObject * newLendObject = [[LendObject alloc] init]; itemViewController.lendObject = newLendObject; [self.lendObjects addObject:newLendObject]; [self.navigationController pushViewController: itemViewController animated:YES]; [itemViewController release]; }

3 Construisez lapplication et testez-la. Tout semble fonctionner et pourtant, lobjet cr napparat pas dans la liste lorsque lutilisateur revient de lcran de saisie ; il faut mettre la liste jour ce moment-l.

Mise jour de la liste


Il faut transmettre un message reloadData la vue en table pour lui indiquer que la liste a volu. 1 Ajoutez une mthode viewWillAppear: dans le chier ObjectListViewController.m :
- (void)viewWillAppear:(BOOL)animated { [self.tableView reloadData]; [super viewWillAppear:animated]; }

2 Construisez lapplication et testez-la. La liste est mise jour, en tout cas il se passe quelque chose, mais le rsultat nest pas trs esthtique. Nous allons amliorer cela.

Amliorer laffichage
Nous emploierons le style de cellule avec un sous-titre pour que lutilisateur puisse voir :
j

le nom de lobjet prt en titre de cellule ;

226

6. Contrles complexes

le nom de lemprunteur et la date demprunt en sous-titre.

1 Modiez la mthode tableView:cellForRowAtIndexPath: dans le chier ObjectListViewController.m :


- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { static NSString *CellIdentifier = @"Cell"; UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; if (cell == nil) { cell = [[[UITableViewCell alloc] initWithStyle: UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier] autorelease]; } LendObject * lendObject = [lendObjects objectAtIndex:indexPath.row]; NSDateFormatter * formatter = [[NSDateFormatter alloc] init]; [formatter setDateFormat:@"dd MMMM yyyy"]; NSString * subTitle = [NSString stringWithFormat: @"prt %@ le %@",lendObject.borrowerName, [formatter stringFromDate:lendObject.lendDate]]; [formatter release]; cell.textLabel.text = [lendObject objectName]; cell.detailTextLabel.text = subTitle; return cell; }

2 Construisez lapplication et testez-la. Cette fois, cest parfait.

Figure 6.22 : Liste des objets prts

Subsiste un petit problme Il ne faut pas quitter lapplication. Autrement, nous perdons tout ce que nous avons saisi. Nous allons rgler cela ds le chapitre suivant.

6.3. Utiliser les Vues en table

227

Pour aller plus loin


Nous navons malheureusement queffleur le vaste sujet des vues en table, de leur cellules et de la navigation entre les vues. Pour approfondir ces sujets, nous vous invitons consulter la documentation dApple soit sur le site des dveloppeurs, soit directement sous XCode : slectionnez la commande Class Browser du menu Project ([Maj]+X+[C]) puis slectionnez loption Flat, all classes. Mme si vous ne lisez pas langlais, vous pouvez consulter la liste des proprits et des mthodes disponibles dans chaque classe et procder vos propres exprimentations. Nous vous proposons quelques challenges par difficult croissante.

Challenges
Challenge 1
Positionner le slectionneur de date la date du jour lors de laffichage de lcran de saisie dun nouvel objet.

Challenge 2
Autoriser la modication des prts dj saisis. Le mme cran peut tre utilis pour la saisie dun nouveau prt ou une modication.

Challenge 3
Ne pas autoriser la sortie de ldition tant que le nom de lobjet et celui de lemprunteur ne sont pas saisis. Prvoir un bouton dannulation qui permette de revenir la liste sans crer dobjet supplmentaire.

Challenge 4
Autoriser la suppression dun lment dune liste.

6.4. Checklist
Nous avons mis en uvre dans ce chapitre des contrles textuels plus complexes, les slectionneurs et les vues en table, ainsi que la navigation entre les vues. Nous avons dtaill le fonctionnement des slectionneurs de date de la classe UIDatePicker et les classes dobjets qui permettent le traitement des dates et leur localisation :

228

6. Contrles complexes

j j j

NSDate ; NSDateFormatter ; NSTimeInterval.

Nous avons vu comment programmer un slectionneur standard et les protocoles qui accompagnent la classe UIPickerView :
j j

UIPickerViewDelegate ; UIPickerViewDataSource.

Nous avons explor les principaux conteneurs utiliss en Objective-C : les tableaux NSArray et les dictionnaires NSDictionary ainsi que leur version modiable. Notre parcours nous a mens enn vers les vues en table qui permettent la navigation dans des structures de donnes complexes :
j j

la classe UITableView ; les protocoles associs UITableViewDelegate et UITableViewData


Source ;

le contrleur de vue de la classe UITableViewController qui prend en charge ces protocoles ; les possibilits daffichage des lignes avec la classe UITable ViewCell.

Nous avons mis en uvre ces techniques pour construire lapplication Emprunts1 qui est presque fonctionnelle. Il ne lui manque plus que la mmoire ; une application qui oublie tout ds quon la quitte nest pas trs utile. Nous la doterons de souvenance ds le prochain chapitre.

6.4. Checklist

229

PERSISTANCE DES DONNES


Utiliser le framework Core Data ......................................................................... 233 Utiliser les listes de proprits ............................................................................ 258 Checklist ........................................................................................................................ 264

231

CHAPITRE 7

Sur un ordinateur, les oprations de sauvegarde des donnes dune application sont souvent explicitement demandes par lutilisateur, qui peut prciser un nom de chier. Sur un iPhone, lutilisateur recherche limmdiatet. Les donnes doivent senregistrer ds que lapplication se termine, loccasion de la prise dun appel entrant par exemple, et lutilisateur souhaite retrouver lapplication telle quil la laisse. Ce chapitre est consacr quelques techniques denregistrement et de rcupration des donnes utilises sur iPhone OS :
j

Core Data est une technologie destine grer des ensembles de donnes labors ; elle prend en charge leur persistance.

Les Listes de Proprits sont une technique trs lgante pour conserver de petits ensembles de donnes.

lissue de ce chapitre, nous aurons dot nos applications ConvertPro et Emprunts de la persistance des donnes. Ce sera galement lopportunit de dcouvrir le motif Notication qui est une technique importante de la programmation Cocoa.

7.1. Utiliser le framework Core Data


Core Data comprend un outil de description dun modle de donnes, quivalent ce que lon trouve sous Access ou 4D, et un ensemble de classes permettant de manipuler les donnes modlises. On peut voir Core Data comme lencapsulation dune base de donnes SQLite dans des objets Objective-C. Le framework masque au programmeur la complexit de gestion dune base de donnes ; il na besoin de connatre ni le langage SQL, ni ladministration des bases de donnes, ni le format denregistrement des donnes, ni lentretien dun cache mmoire. Core Data prend tout cela en charge.

SQLite
SQLite est un gestionnaire de base de donnes lger du domaine public, crit en C ANSI ; le code est donc portable sur diffrentes plateformes et systmes dexploitation. Une base de donnes SQLite tient dans un chier unique, lui-mme portable. Outre Cocoa, ce gestionnaire est utilis en Python, PHP, dans Firefox et il est disponible dans de nombreuses distributions Gnu/Linux.

7.1. Utiliser le framework Core Data

233

Dcrire le modle de donnes


Entits, attributs et relations
Dans la programmation sans Core Data, la partie Modle (au sens du motif MVC) de lapplication est constitue dun ensemble de classes dobjets dnies par le dveloppeur. Avec Core Data, le dveloppeur dcrit le modle de donnes dans un chier spcique au format xcdatamodel, ce chier sera ensuite exploit par le framework pour grer les donnes, les enregistrer et les retrouver ; le travail du dveloppeur est grandement facilit. Dans le modle de donnes, le dveloppeur dnit des entits (entity), lquivalent des classes dobjet, puis les proprits de chaque entit. Suivant leur nature, les proprits sont des attributs (attribute) ou des relations (relationship) :
j

Les attributs sont de type scalaire : boolen ; numrique (entier, dcimal ou ottant) ; date ; chane de caractres.

Les relations sont des rfrences vers dautres entits.

Lorsquune relation est dnie dans une entit A, il faut prciser vers quelle entit B doit tre tablie la relation, ainsi que sa cardinalit, cest--dire les nombres minimum et maximum dobjets de type B avec lesquels chaque objet de type A peut tre en relation. Dans lapplication, les instances dune entit sont gnralement de la classe NSManagedObject. Le dveloppeur peut driver cette classe sil souhaite donner un comportement spcique certaines entits.

Mise en pratique sous XCode


Nous allons crer une nouvelle application sous XCode, Emprunts2, dans laquelle la classe LendObject sera remplace par une entit Core Data du mme nom ; ainsi nous bncierons de la persistance des donnes sans rdiger une ligne de code. Il nous faudra nanmoins adapter le code que nous avions crit dans lapplication Emprunts1 lutilisation du framework Core Data. Crez un nouveau projet sous XCode, de type Navigation-based Application. Cochez la case Use Core Data for storage cette fois, et intitulez le projet Emprunts2.

234

7. Persistance des donnes

Figure 7.1 : Utilisation de Core Data dans un nouveau projet

Vous constaterez lexistence dun chier Emprunts2.xcdatamodel dans le groupe Resources du projet. Il contient le modle de donnes au format Core Data. Nous allons mettre Core Data en uvre avec un modle simple comprenant une relation.

Cration des entits


1 Ouvrez ce chier. Il contient un exemple dentit, Event, avec un attribut timeStamp. Vous pouvez soit dtruire cette entit, soit la modier pour crer une entit LendObject. Pour dtruire lentit, slectionnez-la et pressez la touche []. 2 Crez une entit LendObject et ses attributs selon le tableau :
Tableau 7.1 : Attributs de lentit LendObject Nom Type Optional Non Non Non Transient Non Non Non Indexed Non Non Non

objectName lendDate borrowerName

String Date String

7.1. Utiliser le framework Core Data

235

Figure 7.2 : ajout dattributs dans le modle de donnes

3 Pour chaque attribut, dcochez toutes les cases Optional, Transient et Indexed :
Optional signie que lattribut peut tre absent. Au moment de lenregistrement des donnes, Core Data vrie que tous les attributs non optionnels sont prsents. Si ce nest pas le cas, lenregistrement est refus. Transient signie quil ny a pas de donne sauvegarde pour cet attribut. Une entit qui possde un attribut phmre (Transient) devrait tre dune classe drive de NSManagedObject an dy dnir le comportement relatif cet attribut. Indexed est employ sur les attributs que lon veut utiliser comme critre de recherche.

4 Crez une entit Category avec un attribut selon le tableau :


Tableau 7.2 : Attributs de lentit Category Nom Type Optional Non Transient Non Indexed Oui

categoryName

String

5 Cochez la case Indexed pour lattribut categoryName. Nous aurons besoin de retrouver tous les objets appartenant une catgorie ; cest donc un critre de recherche.

236

7. Persistance des donnes

Cration des relations


1 Slectionnez lentit LendObject et ajoutez une relation (relationShip). Paramtrez cette relation de la faon suivante : Name ; category ; Optional ; non ; Transient ; non ; Destination ; Category ; Inverse ; No Inverse Relationship ; To-Many RelationShip ; Non ; Delete Rule : Nullify.

Figure 7.3 : Paramtres de la relation category de lentit LendObject

Nous venons dindiquer dans le modle de donnes que chaque instance de lentit LendObject doit tre lie une instance (la case Optional est dcoche donc la relation est obligatoire), et une seule, de lentit Category (la case To-Many Relationship est dcoche, un objet prt ne peut avoir quune catgorie). Cest une bonne pratique de dnir une relation inverse pour chacune des relations du modle de donnes. Cela facilite les vrications dintgrit ralises par Core Data. Nous allons donc crer la relation inverse de category. 2 Slectionnez lentit Category et ajoutez une relation paramtre de la faon suivante : Name ; lendObjects ; Optional ; non ; Transient ; non ; Destination ; LendObject ; Inverse ; category ;

7.1. Utiliser le framework Core Data

237

To-Many RelationShip ; Oui ; Delete Rule : Deny.

Figure 7.4 : Paramtres de la relation lendObjects de lentit Category

Cette fois, la case To-Many RelationShip est coche car une catgorie peut contenir plusieurs objets. Nous dnissons galement la relation inverse. La relation inverse de category dans LendObject est automatiquement dnie lendObjects ; les deux relations sont linverse lune de lautre. Le paramtre Delete Rule dnit le comportement de Core Data lorsquun objet est dtruit. Cest une caractristique fonctionnelle importante qui permet de garantir lintgrit des donnes :
j j

No action ; lobjet est dtruit sans autre action. Nullify ; la destruction de lobjet est prise en compte dans la relation inverse (cest la valeur par dfaut). Cascade ; les objets lis lobjet dtruit sont galement dtruits. Deny ; lobjet ne peut tre dtruit tant quil est en relation avec dautres objets.

j j

Nous avons x le paramtre Delete Rule de la relation lendObjets Deny car nous souhaitons que lapplication nous empche de dtruire une catgorie tant quelle contient au moins un objet. Nous allons illustrer ce comportement dans notre application Emprunts2.

Figure 7.5 : Modle de donnes de Emprunts2

3 Enregistrez le chier Emprunts2.xcdatamodel une fois le modle de donnes complt.

238

7. Persistance des donnes

Programmation du modle de donnes


Au lancement de lapplication, le chier Emprunts2.xcdatamodel sera lu et son contenu utilis pour crer une instance de la classe NSManagedObjectModel. Cette dernire contiendra lensemble des descriptions dentit du modle, chacune tant une instance de la classe NSEntityDescription. En pratique, vous naurez pas utiliser directement linstance du modle dans vos programmes, XCode a fait le ncessaire lors de la cration du projet. Examinez les chiers de la classe Emprunts2App Delegate, une proprit prive managedObjectModel y est dnie en lecture seule ; deux autres proprits relatives Core Data y sont galement dnies, nous les examinerons plus loin. Laccesseur de cette proprit est dni explicitement dans le chier Emprunts2App Delegate.m :
- (NSManagedObjectModel *)managedObjectModel { if (managedObjectModel != nil) { return managedObjectModel; } managedObjectModel = [[NSManagedObjectModel mergedModelFromBundles:nil] retain]; return managedObjectModel; }

La mthode +mergedModelFromBundles: cre un modle de donnes en regroupant tous les chiers au format .xcdatamodel contenus dans les paquetages passs en paramtre, ou dans le paquetage de lapplication si le paramtre pass est nil. Cest un motif courant pour crire un accesseur sur une proprit en lecture seule :
j

Si la proprit est diffrente de nil, cest quelle a dj t initialise. Il suffit de la retourner. Si la proprit vaut nil, il faut linitialiser et la retenir, avant de la retourner lappelant.

Comprendre le fonctionnement de Core Data


La pile Core Data
Le fonctionnement de Core Data ncessite la collaboration de plusieurs objets qui constituent la pile Core Data :
j

Le modle de donnes de la classe NSManagedObjectModel contient la description des entits manipules.

7.1. Utiliser le framework Core Data

239

Les units de stockage de la classe NSPersistentStore grent les accs aux diffrents chiers dans lesquels les donnes sont conserves. Le coordonnateur des units de stockage de la classe NSPersistent StoreCoordinator a la responsabilit dunier les diffrentes units de stockage. Les contextes Core Data, instances de la classe NSManaged ObjectContext, sont la principale interface du dveloppeur avec les donnes Core Data.

La plupart du temps, on utilise une pile Core Data offrant une seule unit de stockage (donc un seul chier de donnes) et un seul contexte Core Data.

Figure 7.6 : Pile Core Data dans le cas dune unit de stockage et dun contexte uniques

Le contexte Core Data est lobjet manipul par le dveloppeur pour crer, dtruire ou rechercher des instances dentits Core Data. Tous nos contrleurs de vue auront donc une proprit managedObject Context.

240

7. Persistance des donnes

Initialisation dune pile Core Data


Avant de pouvoir manipuler le contexte Core Data, il faut initialiser les diffrents lments de la pile. Encore une fois, XCode a ralis tout le travail lors de la cration du projet ; la pile Core Data est construite par le dlgu de lapplication et nous naurons pas ajouter une ligne de code. 1 Ouvrez le chier Emprunts2AppDelegate.m pour voir ce qui se passe au lancement de lapplication.

Options de lancement
Les mthodes applicationDidFinishLaunching: et application: didFinishLaunchingWithOptions: sont quivalentes. La seconde permet de rcuprer les paramtres de lancement transmis lapplication, par le systme des notications distance par exemple.

2 Commencez par lexamen de la mthode applicationDid FinishLaunching:. Aprs avoir cr le contrleur de vue principal rootViewController, la proprit managedObjectContext de ce dernier est initialise avec celle du dlgu de lapplication :
rootViewController.managedObjectContext = self.managedObjectContext;

Cette instruction fait beaucoup plus que donner une valeur une proprit. Le dlgu dapplication offre trois proprits dnies en lecture seule :
@property (nonatomic, retain, readonly) NSManagedObjectModel *managedObjectModel; @property (nonatomic, retain, readonly) NSManagedObjectContext *managedObjectContext; @property (nonatomic, retain, readonly) NSPersistentStoreCoordinator *persistentStoreCoordinator;

Nous avons dj examin laccesseur de la proprit managed ObjectModel. Les deux autres accesseurs sont raliss selon le mme motif : si la proprit vaut nil, elle est initialise par laccesseur. Regardez le code de laccesseur managedObjectContext, son premier appel dclenche en cascade lappel des autres accesseurs et donc linitialisation de la pile Core Data. Considrons les instructions dinitialisation dans lordre selon lequel elles sont excutes, en supprimant les contrles derreur et les appels successifs, et en ajoutant des tapes intermdiaires, pour nous concentrer sur lessentiel, la cration de chacun des lments de la pile Core Data :

7.1. Utiliser le framework Core Data

241

Identication du chier de donnes utiliser : utilisation dune fonction du framework Foundation pour obtenir le chemin du dossier des documents par dfaut :
NSString *directory = [NSSearchPathForDirectoriesInDomains (NSDocumentDirectory,NSUserDomainMask, YES) lastObject];

construction du chemin daccs vers le chier en ajoutant son nom Emprunts2.sqlite au chemin du dossier des documents par dfaut :
NSString *storeFile = [directory stringByAppendingPathComponent: @"Emprunts2.sqlite"];

construction dun URL permettant daccder au chier de donnes.


NSURL *storeUrl = [NSURL fileURLWithPath: storeFile];
j

Cration et initialisation du modle de donnes :


managedObjectModel = [[NSManagedObjectModel mergedModelFromBundles:nil] retain];

Cration et initialisation du coordonnateur des units de stockage et initialisation avec le modle de donnes : cration puis initialisation avec le modle de donnes :
persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];

ajout dune unit de stockage de type SQLite pointant sur le chier Emprunts2.sqlite :
NSError *error = nil; [persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeUrl options:nil error:&error];
j

Cration et initialisation du contexte Core Data : cration :


managedObjectContext = [[NSManagedObjectContext alloc] init];

initialisation avec le coordonnateur des units de stockage :


[managedObjectContext setPersistentStoreCoordinator: persistentStoreCoordinator];

242

7. Persistance des donnes

Nous naurons pas modier ces lignes de code mais cest toujours intressant de comprendre comment cela fonctionne. Il y a vraisemblablement des aspects de ce code que vous ne matrisez pas. Ce nest pas grave, vous nen aurez pas besoin pour utiliser Core Data. Nhsitez pas consulter la documentation an dapprofondir ces sujets. Au nal, nous disposons dune proprit managedObjectContext qui est un contexte Core Data utilisant le modle de donnes Emprunts2. xcdatamodel de notre application et le chier de donnes Emprunts2.sqlite dans le dossier des documents de lapplication sur liPhone.

Utilisation dans une Vue en Table


Le contrleur de rsultats de recherche
Le framework Core Data propose une classe NSFetchedResults Controller, un contrleur de rsultats de recherche, qui facilite lcriture du dlgu et de la source de donnes dune vue en table. Vriez que le contrleur de vue principal du projet Emprunts2 (RootViewController) offre une proprit fetchedResultsController, instance de cette classe. Chaque instance de NSFetchedResultsController est associe un contexte Core Data (proprit managedObjectContext) et une requte Core Data (proprit fetchRequest). Une requte est une instance de la classe NSFetchRequest, elle permet de trouver les instances dune entit qui rpondent un critre donn ; ces instances sont celles que lon souhaite afficher dans la vue en table. Nos vues en table noffrent quune section mais nous pourrions souhaiter que les lments de la vue en table soient regroups en fonction dun critre de tri. Si nous activons cette fonction (nous verrons comment un peu plus loin), la proprit sections du contrleur de rsultats de recherche est un tableau dont chaque lment dcrit une section. Ce sont des objets qui rpondent au protocole <NSFetchedResultsSectionInfo>, offrant les proprits suivantes :
j j j

numberOfObjects ; nombre de lignes dans la section ; objects ; tableau contenant les objets de la section ; name ; nom de la section, gnralement affich comme titre de la section ; indexTitle ; titre de lindex, gnralement utilis lorsquun index est affich sur la droite de la vue en table.

7.1. Utiliser le framework Core Data

243

Les principales mthodes de la classe NSFetchedResultsController sont :


j

performFetch: qui excute la requte associe au contrleur et retourne YES si lexcution sest bien droule, NO autrement. Cette mthode prend en paramtre un pointeur sur une rfrence dinstance de la classe NSError qui nous fournit des informations dans le cas o la requte ne sest pas bien droule. objectAtIndexPath: qui retourne linstance dentit (sous forme dinstance de NSManagedObject) qui doit tre affiche sur la ligne identie par linstance de NSIndexPath passe en paramtre.

Cette classe contient galement un dlgu rpondant au protocole <NSFetchedResultsControllerDelegate> qui est inform de toute modication de la liste des objets. Le contrleur de vue en table qui contient le contrleur de rsultats de recherche est gnralement dni comme son dlgu pour informer la vue en table que les donnes ont t modies. Vriez que la classe RootViewController du projet Emprunts2 rpond ce protocole et en implmente notamment les mthodes controllerWilChangeContent: et controllerDidChangeContent:.

Gestion des erreurs


Voici la pratique recommande par Apple concernant la dtection et le traitement des erreurs :
j

Les fonctions ou mthodes susceptibles de ne pas sexcuter correctement retournent NO ou nil en cas derreur. La valeur de retour est systmatiquement teste dans le code appelant. Une rfrence un objet NSError est passe par rfrence et initialise en cas derreur.

passage par rfrence


En langage C, donc aussi en Objective-C, les fonctions et mthodes ne peuvent pas modier les paramtres qui leur sont transmis. On dit que les paramtres sont passs par valeur. Le seul moyen de modier un paramtre est donc de passer son adresse, cest ce que lon appelle le passage de paramtre par rfrence ou par adresse. Dans cet exemple, le paramtre de la mthode performFetch: est de type (NSError **). On lui passe ladresse dune error de type NSError * en utilisant loprateur de rfrence du langage C "&error".

244

7. Persistance des donnes

Les potentialits derreur sont nombreuses quand on utilise Core Data : incompatibilit entre un modle de donnes et une unit de stockage, entit inexistante dans un modle de donnes, erreur de cardinalit dans une relation, etc. Plusieurs mthodes du framework adoptent donc la mthode de dtection derreur prconise. Par exemple, la mthode performFetch: de la classe NSFetchedResults Controller sutilise de la faon suivante :
NSError *error = nil; if (![fetchedResultsController performFetch:&error]) { // Traitement de lerreur }

Une instance de la classe NSError est un conteneur permettant de transmettre des informations plus riches quun simple code derreur, facilitant ainsi le diagnostic et le traitement de lerreur. Les principales mthodes de la classe NSError sont rsumes dans le tableau.
Tableau 7.3 : Principales mthodes de la classe NSError Thme Cration Signature Objet Cre une instance de la classe avec les paramtres domain, code et dict. Chane de caractres identiant le domaine de lerreur Code derreur Dictionnaire contenant des informations complmentaires sur le contexte de lerreur

+ (id) errorWithDomain: (NSString *)domain code: (NSInteger)code userInfo: (NSDictionary *)dict

Proprits (NSString *)domain

(NSInteger)code (NSDictionary *) userInfo

Les erreurs produites par le framework Core Data sont gnralement du domaine NSCocoaErrorDomain. Une erreur est identie par son domaine et son code. Nous verrons un exemple de traitement derreur dans lapplication Emprunts2.

Enregistrement des donnes Core Data


La cration de la pile Core Data, au lancement de lapplication, permet de mettre en place la lecture du chier de donnes. La structure de donnes contenue dans le chier est reproduite au besoin dans le contexte Core Data. Toutes les modications effectues par lapplication (modication des proprits, cration ou suppression dobjets) sont enregistres dans le contexte. Elles sont enregistres dans le chier de donnes lorsque le contexte reoit un message save:.

7.1. Utiliser le framework Core Data

245

La mthode save: applique la mthode standard pour la dtection derreur. Elle retourne un boolen et prend en paramtre une variable NSError passe par rfrence. Cette mthode doit tre appele notamment chaque fois quun objet est cr ou dtruit car ces oprations sont des sources potentielles derreur ; il faut que lutilisateur soit inform ds que possible sil ralise une action interdite. Il faut galement enregistrer les modications effectues dans le contexte lorsque lapplication est sur le point de quitter. XCode gnre le code ncessaire dans le dlgu dapplication, la mthode applicationWillTerminate est appele juste avant que lapplication ne quitte :
- (void)applicationWillTerminate: (UIApplication *)application { NSError *error = nil; if (managedObjectContext != nil) { if ([managedObjectContext hasChanges] && ![managedObjectContext save:&error]) { NSLog(@"Unresolved error %@, %@", error, [error userInfo]); abort(); } } }

Dans le code propos par dfaut, un message est affich dans la console avec la fonction NSLog. Ce fonctionnement est suffisant pendant le dveloppement, mais pour une version distribue, laffichage dune alerte serait plus appropri.

Accs aux proprits des objets Core Data


Les instances dentits Core Data sont manipules dans le code comme des instances de la classe NSManagedObject, quel que soit le type de lentit. Les attributs et relations sont accessibles en utilisant les mthodes du motif KVC sur cette instance :
j j

(id)valueForKey:(NSString *)key pour obtenir une proprit ; (void)setValue:(id)value forKey:(NSString *)key pour modier une proprit.

Dans les deux cas, la chane de caractres key est le nom de la proprit tel quil a t dni dans le modle de donnes pour lentit. La classe NSManagedObject vrie que la cl employe est un attribut ou une relation de lentit considre.

246

7. Persistance des donnes

Formuler des requtes


Lapplication Emprunts2, comme lapplication Emprunts1 du chapitre prcdent, prsente lutilisateur une liste de catgories, puis dans la vue suivante la liste des objets prts qui appartiennent cette catgorie. Chacune de ces listes est le rsultat dune requte Core Data affiche dans une vue en table avec son propre contrleur de vue :
j

La premire liste utilise une requte qui porte sur lentit Category et dont le rsultat est lensemble de toutes les instances de lentit. La seconde liste porte sur lentit LendObject. Nous souhaitons conserver dans cette liste uniquement les objets lis par la relation category la catgorie dont lattribut categoryName est le nom slectionn par lutilisateur dans la liste prcdente.

Ralisation dune requte


Examinez la classe RootViewController du projet Emprunts2, en particulier laccesseur de la proprit fetchResultsController. Cette mthode initialise le contrleur de rsultat de requte, en particulier la requte qui y est associe. Une requte est reprsente par une instance de la classe NSFetched
Request :
j j

Sa proprit entity reprsente lentit concerne par la requte. La proprit fetchBatchSize prend la valeur 20, pour limiter le nombre dobjets lus en une fois dans le chier de donnes. Cela permet dconomiser la mmoire. Seules quelques lignes sont affiches un instant donn dans une vue en table. Il est donc inutile de lire plus de 20 valeurs la fois. La proprit sortDescriptors est un tableau de descripteurs de tri, instances de NSSortDescriptor. Un descripteur de tri peut tre rsum comme lassociation du nom dune proprit de lentit et dun ordre de tri, ascendant ou descendant.

Cration de la requte pour les catgories


Modiez la mthode fetchResultsController dans le chier RootViewController.m pour y dnir lentit et le critre de tri souhaits.
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init]; NSEntityDescription *entity = [NSEntityDescription entityForName:@"Category" inManagedObjectContext:managedObjectContext]; [fetchRequest setEntity:entity]; 247

7.1. Utiliser le framework Core Data

[fetchRequest setFetchBatchSize:20]; NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"categoryName" ascending:YES]; NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil]; [fetchRequest setSortDescriptors:sortDescriptors];

Cration de la requte pour les objets


Nous avons besoin dun contrleur de vue en table pour la liste des objets. Ce contrleur sera analogue celui des catgories ; aussi, nous allons en faire un clone.

Cration du contrleur de vue


1 Dupliquez les chiers RootViewController.h et RootViewController.m sous Finder, dans le dossier du projet. Renommez-les respectivement ObjectListViewController.h et ObjectListViewController.m. Ajoutez ces 2 nouveaux chiers au projet Emprunts2 sous XCode. 2 Dans ces deux chiers, modiez toutes les occurrences de texte RootViewController en ObjectListViewController. Vous pouvez pour cela utiliser la fonction de recherche dans un chier de XCode (X+[F]). 3 Modiez la mthode fetchResultsController pour y adapter lentit et le critre de tri souhaits, respectivement LendObject et lendDate.

Dnition dun critre de recherche


Le critre de recherche est donn par la proprit predicate de la requte NSFetchRequest. Cest une instance de la classe NSPredicate qui doit tre initialise avec une chane de caractres. Ajoutez une proprit category de classe NSManagedObject la classe ObjectListViewController que nous venons de crer. Ajoutez les lignes suivantes dans la mthode fetchResultsController du chier ObjectListViewController.m pour slectionner seulement les objets de la catgorie choisie :
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"category.categoryName like %@", [self.category valueForKey:@"categoryName"]]; [fetchRequest setPredicate:predicate];

Prdicat
Un prdicat est une proposition dont la valeur Vrai ou Faux dpend dune ou plusieurs variables. Le prdicat est valu pour chaque instance dentit. Seuls sont retenus les objets pour lesquels le prdicat est vrai.

248

7. Persistance des donnes

Le prdicat le plus simple est une expression de comparaison dun attribut une valeur. Un attribut est dsign par son nom. Ici, nous avons utilis la notation pointe category.categoryName ; cela signie que nous nous intressons lattribut categoryName de lobjet li par la relation category lentit sur laquelle nous effectuons la recherche (LendObject). On peut employer les oprateurs standard pour effectuer les comparaisons telles que =, < et >. Les chanes de caractres sont compares avec loprateur like qui admet les caractres joker * et ?. Il est galement possible de combiner plusieurs expressions avec les oprateurs AND, OR et NOT. Lcriture des prdicats fait lobjet dun guide complet dans la documentation Apple (Predicate Programming Guide).

Connecter les deux contrleurs de vue


Le contrleur de la vue des objets vient dtre bauch par clonage du contrleur de vue des catgories. Il faut maintenant tablir les connexions entre ces deux contrleurs.

Classe ObjectListViewController
1 Modiez la mthode viewDidLoad pour dnir le titre de la vue. Il faut galement supprimer le bouton Edit gauche de la barre de navigation. Il sera remplac par le bouton de retour.
self.title = [self.category valueForKey:@"categoryName"]; //self.navigationItem.leftBarButtonItem=self.editButton Item;

2 Modiez les mthodes tableView:cellForRowAtIndexPath: et configureCell:atIndexPath: pour crer les cellules de la vue en table.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { static NSString *CellIdentifier = @"ObjectCell"; UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; if (cell == nil) { cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier] autorelease]; [self configureCell:cell atIndexPath:indexPath]; return cell; } - (void)configureCell:(UITableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath { cell.accessoryType =
7.1. Utiliser le framework Core Data

249

UITableViewCellAccessoryDisclosureIndicator; NSManagedObject *managedObject = [fetchedResultsController objectAtIndexPath:indexPath]; cell.textLabel.text = [managedObject valueForKey:@"objectName"]; NSDateFormatter * formatter = [[NSDateFormatter alloc] init]; [formatter setDateFormat:@"dd MMMM yyyy"]; NSString * subTitle = [NSString stringWithFormat: @"prt %@ le %@", [managedObject valueForKey:@"borrowerName"], [formatter stringFromDate: [managedObject valueForKey:@"lendDate"]]]; [formatter release]; cell.detailTextLabel.text = subTitle; }

Cette suite dinstructions ressemble celle que nous avons crite pour lapplication Emprunts1. Notez toutefois ces diffrences :
j

Nous avons un identiant de cellule ObjectCell, pour le distinguer de celui que nous utiliserons pour la vue en table des catgories. Nous utilisons le contrleur de rsultats de requte an dobtenir lobjet afficher dans la cellule. Nous employons le motif KVC pour accder aux attributs de lobjet Core Data.

Fichier RootViewController.m
Cest dans le chier RootViewController.m que nous crirons le code an dutiliser le contrleur de la vue en table pour les objets. Procdez ainsi : 1 Ajoutez une clause dimportation de la dclaration de ce contrleur :
#import "ObjectListViewController.h"

2 Dnissez un titre de la vue en table dans la mthode didLoadView. Autrement, vous ne distinguerez pas le bouton de retour dans la vue suivante.
self.title = @"Catgories";

3 Dnissez les cellules dans la mthode configureCell:atIndex Path: :


- (void)configureCell:(UITableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath { NSManagedObject *managedObject = [fetchedResultsController objectAtIndexPath:indexPath];

250

7. Persistance des donnes

cell.textLabel.text = [managedObject valueForKey:@"categoryName"]; cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;

4 Programmez laffichage de la liste des cellules lorsquune catgorie est slectionne. Veillez initialiser les proprits managed ObjectContext et category avant dactiver le contrleur de vue.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { NSManagedObject *selectedCategory = [fetchedResultsController objectAtIndexPath:indexPath]; ObjectListViewController * objectListViewController = [[ObjectListViewController alloc] initWithStyle:UITableViewStylePlain]; objectListViewController.managedObjectContext = [fetchedResultsController managedObjectContext]; objectListViewController.category = selectedCategory; [self.navigationController pushViewController:objectListViewController animated:YES]; [objectListViewController release]; }

5 Construisez lapplication pour vrier quil ny a pas derreur dans votre code. Vous pouvez galement lessayer sur le simulateur mais ce premier test sera trs frustrant car la liste des catgories est vide. Nous allons maintenant crire le code pour crer des catgories.

Ajouter un objet
Crer une instance dentit
La cration dune instance dentit ncessite le nom de lentit et un contexte Core Data. Elle se droule en deux tapes :
j j

crer une description de lentit ; crer une instance de NSManagedObject et linitialiser pour quelle devienne une instance de lentit souhaite, tout en linsrant dans le contexte.

Par exemple, si nous souhaitons crer une instance de lentit LendObject :


NSEntityDescription *entity = [NSEntityDescription entityForName:@"LendObject" inManagedObjectContext: managedObjectContext]; NSManagedObject *newLendObject = [[NSManagedObject alloc]

7.1. Utiliser le framework Core Data

251

initWithEntity: entity insertIntoManagedObjectContext: managedObjectContext];

Classes drives de NSManagedObject


Mme sil est dclar de type NSManagedObject *, lobjet retourn par la mthode initWithEntity:insertIntoManagedObjectContext: est une instance de la classe dnie pour cette entit dans le modle de donnes.

Crer une vue dtaille pour les catgories


Lors de sa cration, il faut que lutilisateur puisse saisir le nom de la catgorie. Vous devez donc crer une vue spcique et son contrleur : 1 Sous XCode, crez un nouveau chier pour une classe qui drive de UIViewController. Cochez loption With XIB for user interface. Intitulez cette classe CategoryViewController. 2 Ouvrez le chier CategoryViewController.xib pour y tracer linterface utilisateur. Vous avez besoin uniquement dun champ de texte pour saisir le nom de la catgorie.

Figure 7.7 : interface utilisateur pour la saisie dune catgorie

3 Sous XCode, modiez la classe CategoryViewController : Ajoutez une proprit NSManagedObject * category. Ajoutez un outlet UITextField * categoryNameField. Modiez la mthode viewDidLoad. Crez une mthode viewWillDisappear: :
- (void)viewDidLoad { self.categoryNameField.text = [self.category valueForKey:@"categoryName"]; self.title = @"Catgorie"; [super viewDidLoad]; } - (void)viewWillDisappear:(BOOL)animated{ [self.category setValue:self.categoryNameField.text forKey:@"categoryName"];

252

7. Persistance des donnes

[super viewWillDisappear:animated]; }

4 Connectez loutlet au champ de texte sous Interface Builder.

Modier le contrleur de vue principal


Il faut maintenant prvoir lactivation de la vue que nous venons de raliser. Le modle dapplication que nous avons indiqu lors de la cration du projet dispose un bouton dajout dans la barre de navigation. Laction connecte ce bouton est la mthode insert NewObject prpare par XCode. 1 Modiez cette mthode dans le chier RootViewController.m :
- (void)insertNewObject { NSManagedObjectContext *context = [fetchedResultsController managedObjectContext]; NSEntityDescription *entity = [[fetchedResultsController fetchRequest] entity]; NSManagedObject *newManagedObject = [NSEntityDescription insertNewObjectForEntityForName:[entity name] inManagedObjectContext:context]; [newManagedObject setValue:@"saisissez le nom" forKey:@"categoryName"]; NSError *error = nil; if (![context save:&error]) { NSLog(@"Unresolved error %@, %@", error, [error userInfo]); abort(); } CategoryViewController * itemViewController = [[CategoryViewController alloc] initWithNibName:@"CategoryViewController" bundle:nil]; itemViewController.category = newManagedObject; [self.navigationController pushViewController:itemViewController animated:YES]; [itemViewController release]; }

2 Ajoutez une clause #import "CategoryViewController.h" en tte du chier. Vous reconnaissez dans le code propos par XCode les instructions pour crer un objet Core Data. La particularit ici est que le contexte et la description de lentit sont extraits du contrleur de rsultats de requte. Ainsi le nom de lentit est inscrit un seul endroit dans le chier RootViewController.m ; il est plus facile dassurer la maintenance du code.

7.1. Utiliser le framework Core Data

253

Nous initialisons lobjet nouvellement cr puisque la prsence de lattribut est obligatoire, puis nous enregistrons le contexte. Les autres instructions sont classiques : cration du contrleur de vue pour la saisie du nom de la catgorie, initialisation de ses proprits et activation.

Challenge
Vous savez maintenant comment ajouter une instance dentit un contexte Core Data. Nous vous proposons donc de mettre en uvre la mme mthode pour la fonction dajout dun objet prt. Ce challenge est assez facile. Vous pouvez adapter le contrleur de vue LendObjectViewController et son chier NIB que nous avions raliss pour lapplication Emprunts1. Nous rencontrerons des challenges plus complexes dans la suite de ce chapitre.

Supprimer un objet
Si vous avez test votre application Emprunts2, vous avez constat que la vue principale comprenait un bouton Edit gauche de la barre de navigation. Si vous avez eu la curiosit de toucher ce bouton, vous avez pu voir une vue en table en mode dition.

Figure 7.8 : Mode dition dune vue en table

Programmation du mode dition


Le bouton Edit est activ dans la mthode viewDidLoad du contrleur de vue principal.
self.navigationItem.leftBarButtonItem = self.editButtonItem;

254

7. Persistance des donnes

Par dfaut, en mode dition, un bouton permettant la suppression est affich dans chaque cellule. Ce comportement peut tre modi en implmentant la mthode tableView:editingStyleForRowAt IndexPath: dans le dlgu de la vue en table (gnralement son contrleur). Cette mthode doit retourner une valeur du type numr UITableViewCellEditingStyle pour dnir le style de bouton afficher dans la cellule.
Tableau 7.4 : Valeurs du type numr UITableViewCellEditingStyle Bouton C07-10.png C07-11.png Valeur

UITableViewCellEditingStyleNone UITableViewCellEditingStyleDelete UITableViewCellEditingStyleInsert

Lorsque la vue en table est en mode dition et que lutilisateur touche le bouton ddition dune cellule, la source de donnes (gnralement le contrleur de la vue en table) reoit le message tableView:commitEditingStyle:forRowAtIndexPath:. Nous allons modier cette mthode propose par XCode.

Vrication la suppression dune catgorie


La suppression dun objet seffectue par lenvoi du message deleteObject: au contexte Core Data, avec lobjet supprimer pass en paramtre. Dans le modle de donnes, nous avons donn la valeur Deny au paramtre Delete Rule de la relation lendObjects de lentit Category. Nous souhaitons en effet interdire la suppression dune catgorie tant quelle contient au moins un objet. Cette rgle concernant la suppression fait partie dun ensemble plus global nomm rgles dintgrit.

Rgles dintgrit
Ce sont les rgles que doivent respecter les donnes enregistres dans une base de donnes an que cet ensemble de donnes conserve un sens.

Les rgles dintgrit sont vries par Core Data au moment de lenregistrement du contexte. Nous allons donc tester les valeurs retournes par la mthode save:, en particulier linstance de NSError, pour savoir si nous sommes dans le cas de la rgle de suppression :

7.1. Utiliser le framework Core Data

255

j j

Le domaine de lerreur est NSCocoaErrorDomain. Le code derreur est NSValidationRelationshipDeniedDeleteError.

Le traitement de cette erreur est alors :


j j

afficher un message dalerte pour informer lutilisateur ; rinsrer lobjet dtruit dans le contexte :
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath { if (editingStyle == UITableViewCellEditingStyleDelete) { NSManagedObjectContext *context = [fetchedResultsController managedObjectContext]; NSManagedObject *objectToDelete = [fetchedResultsController objectAtIndexPath:indexPath]; [context deleteObject:objectToDelete]; NSError *error = nil; if (![context save:&error]) { if (([error.domain isEqualToString:NSCocoaErrorDomain]) && (error.code == NSValidationRelationshipDeniedDeleteError)){ UIAlertView * alertView = [[UIAlertView alloc] initWithTitle:@"Suppression dune catgorie" message:@"Il nest pas autoris de supprimer une catgorie pour laquelle il existe des objets prts" delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil]; [alertView show]; [alertView release]; } [context insertObject:objectToDelete]; } } }

Liste des codes derreur


La liste des codes derreur de Core Data est dans la documentation Core Data Constants Reference.

Construisez et testez lapplication. Son comportement devrait tre satisfaisant maintenant.

256

7. Persistance des donnes

Figure 7.9 : Dtection derreur lors de la suppression

Challenges
Challenge 1
Finalisez lapplication Emprunts2 pour permettre lutilisateur de supprimer un objet prt.

Challenge 2
Ajoutez une fonctionnalit permettant lutilisateur de voir la liste de tous les objets prts. Pour que cette fonction soit utilisable, il faut penser permettre lutilisateur de prciser la catgorie dun objet lors de sa cration.

Challenge 3
Un challenge purement technique, les classes RootViewController et ObjectListViewController se ressemblent beaucoup. Il y a de nombreuses lignes de code dupliques, ce qui ne favorise pas la maintenance. crivez une classe qui puisse tre utilise pour remplacer ces deux contrleurs de vue.

7.1. Utiliser le framework Core Data

257

7.2. Utiliser les listes de proprits


Core Data est un trs bon framework mais sans doute lourd dans les situations o seules quelques donnes sont concernes. Les Listes de proprits (property list) sont plus faciles employer.

Format des listes de proprits


Vous avez dj utilis une liste de proprit : le chier au format .plist que lon trouve dans tous les projets et dans lequel vous avez dni licne de lapplication.

Figure 7.10 : Exemple de liste de proprits

Ce chier est au format XML. Il contient un dictionnaire compos dun ensemble de couples (cl, valeur) :
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>CFBundleDevelopmentRegion</key> <string>English</string> <key>CFBundleDisplayName</key> <string>${PRODUCT_NAME}</string> <key>CFBundleExecutable</key> <string>${EXECUTABLE_NAME}</string> <key>CFBundleIconFile</key> <string></string> <key>CFBundleIdentifier</key> <string>com.yourcompany. ${PRODUCT_NAME:rfc1034identifier}</string> <key>CFBundleInfoDictionaryVersion</key> <string>6.0</string> <key>CFBundleName</key> <string>${PRODUCT_NAME}</string> <key>CFBundlePackageType</key> 258

7. Persistance des donnes

<string>APPL</string> <key>CFBundleSignature</key> <string>????</string> <key>CFBundleVersion</key> <string>1.0</string> <key>LSRequiresIPhoneOS</key> <true/> <key>NSMainNibFile</key> <string>MainWindow</string> </dict> </plist>

Utilisation des listes de proprits


Accs une liste de proprits
Une liste de proprits est un dictionnaire, la classe NSDictionary dispose donc des mthodes pour y accder :
j

+ (id)dictionaryWithContentsOfFile:(NSString *)path permet de crer un dictionnaire partir de la liste de proprits dont le chemin daccs est pass en paramtre. (BOOL)writeToFile:(NSString *)path atomically:(BOOL)flag permet denregistrer le rcepteur dans un chier dont le chemin daccs est pass en paramtre. Le paramtre atomically permet de garantir lintgrit du chier. En cas derreur lors de lcriture, le chier nest pas modi si ce paramtre vaut YES.

Types de donnes
Une liste de proprits est donc un dictionnaire soumis quelques limitations :
j j

Les cls sont obligatoirement des chanes de caractres. Les valeurs doivent tre de lun des types prdnis ci-aprs.

Le tableau indique, pour chaque type autoris, ltiquette utilise dans le chier XML et la classe dobjet correspondante.
Tableau 7.5 : Types de donnes autoriss dans une liste de proprits Type Tableau Dictionnaire Chane de caractres Data Date lment XML Classe Objective-C

<array> <dict> <string> <data> <date>

NSArray NSDictionary NSString NSData NSDate

7.2. Utiliser les listes de proprits

259

Tableau 7.5 : Types de donnes autoriss dans une liste de proprits Type Nombre entier Nombre rel Boolen lment XML Classe Objective-C

<integer> <real> <true/> ou <false/>

NSNumber (intValue) NSNumber (floatValue) NSNumber (boolValue)

Mise en pratique
Nous allons reprendre notre application Convertisseur2 pour la doter de la persistance des donnes. Le principe sera le suivant :
j

Des mthodes pour lire et crire un chier sont ajoutes la classe


Convertisseur. Cest elle qui dtient les donnes que nous souhai-

tons persistantes.
j

Le chier de donnes est lu au dmarrage de lapplication puis crit lorsque lapplication va quitter.

Modier la classe Convertisseur


1 Ajoutez la dclaration des mthodes dans le chier Convertisseur.h :
- (BOOL)readFromFile:(NSString *)path; - (BOOL)writeToFile:(NSString *)path atomically:(BOOL)flag;

Ces mthodes prennent les mmes paramtres que les mthodes de NSDictionary pour la lecture et lcriture dune liste de proprits. Leur travail consistera essentiellement constituer un dictionnaire intermdiaire. 2 Ajoutez-les dans le chier Convertisseur.m.
- (BOOL)readFromFile:(NSString *)path{ if ([self init]) { NSDictionary * dict = [NSDictionary dictionaryWithContentsOfFile:path]; if (dict) { dollar = [[dict objectForKey:@"dollar"] floatValue]; euro = [[dict objectForKey:@"euro"] floatValue]; dollarsPourUnEuro = [[dict objectForKey:@"dollarsPourUnEuro"] floatValue]; } } return self; } - (BOOL)writeToFile:(NSString *)path atomically:(BOOL)flag{

260

7. Persistance des donnes

NSDictionary *dict = [NSDictionary dictionaryWithObjects: [NSArray arrayWithObjects: [NSNumber numberWithFloat:self.dollar], [NSNumber numberWithFloat:self.euro], [NSNumber numberWithFloat:self.dollarsPourUnEuro],nil] forKeys:[NSArray arrayWithObjects: @"dollar",@"euro",@"dollarsPourUnEuro",nil]]; return [dict writeToFile:path atomically:flag]; }

Classe NSNumber
La classe NSNumber utilise prcdemment sert empaqueter un nombre, entier ou ottant, dans un objet. On ne peut pas insrer directement une valeur de type int ou float dans un conteneur NSArray ou NSDictionary. On utilise donc la classe NSNumber. On emploie galement cette classe avec le motif KVC.
Tableau 7.6 : Principales mthodes de la classe NSNumber Thme Crer un nombre Signature de la mthode Remarque

+ (NSNumber *) number <Type> doit tre remplac par Wih<Type>: (type) value lun des types scalaires ci-aprs.

Obtenir la valeur dun (type) <type>Value nombre

Les types scalaires utilisables sont : Bool, Char, Double, Float, Int, Integer, Long, LongLong, Short, UnsignedChar, UnsignedInt, Unsigned Integer, UnsignedLong, UnsignedLongLong et UnsignedShort. Le nom du type utilis prend une majuscule dans les mthodes +number, et une minuscule dans les mthodes Value. Par exemple :
+ (NSNumber *) numberWihLongLong: (long long) value - (long long) longLongValue

Lecture au dmarrage de lapplication


Jusqu prsent, nous avons ralis les initialisations dans le dlgu dapplication. Dans lapplication Convertisseur2, ce dlgu na pas de proprit convertisseur contrairement au contrleur de la vue principale. Nous aurons donc moins de code modier si linitialisation est ralise dans ce dernier.

Identication du chier
Nous allons nous inspirer de la technique utilise pour identier et grer lunit de stockage Core Data.

7.2. Utiliser les listes de proprits

261

1 Dclarez une proprit NSString * storeFile dans linterface de la classe MainViewController puis ajoutez le synthtiseur des accesseurs pour cette proprit dans le chier MainViewController.m 2 Ajoutez la dnition de laccesseur :
- (NSString *)storeFile { if (!storeFile){ NSString *directory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject]; storeFile = [directory stringByAppendingPathComponent: @"Convertisseur.plist"]; [storeFile retain]; } return storeFile; }

Nous utiliserons un chier nomm Convertisseur.plist situ dans le dossier des documents.

Initialisation
Les initialisations de linterface utilisateur doivent tre ralises dans la mthode viewDidLoad du contrleur de vue, cest le bon endroit pour lire la liste de proprits et initialiser les champs de texte :
- (void)viewDidLoad { [super viewDidLoad]; [self.convertisseur readFromFile:self.storeFile]; euroField.text = stringWithCurrency(self.convertisseur.euro); dollarField.text = stringWithCurrency(self.convertisseur.dollar); }

La proprit storeFile est obtenue en passant par son accesseur ; cela garantit quelle contiendra le chemin du chier utiliser.

criture lorsque lapplication quitte


Lorsque lapplication se termine, nous savons que le message applicationWillTerminate est transmis au dlgu dapplication. Ce serait lendroit idal pour sauvegarder lobjet convertisseur dans la liste de proprits Convertisseur.plist. Mais la lecture du chier est ralise dans le contrleur de vue. Cest ce dernier qui possde les proprits convertisseur et storeFile. Il est donc logique que lcriture du chier soit galement ralise dans le contrleur de vue. Il faut que le contrleur de vue soit prvenu lorsque lapplication va se terminer, de la mme faon que le dlgu dapplication.

262

7. Persistance des donnes

Notications
Le framework Cocoa Touch propose le mcanisme des notications. Chaque fois quun vnement important se produit, le Centre de notication est inform. Les objets qui souhaitent tre informs de ces vnements doivent sabonner au centre de notication. Comment connatre la liste des vnements disponibles ? Dites-vous que toutes les classes possdant un dlgu sont susceptibles dmettre des notications. titre dexemple, le tableau ci-aprs indique quelques notications mises par les classes que nous connaissons dj.
Tableau 7.7 : Exemples de notifications mises Classe Notification

UITextField

UITextFieldTextDidBeginEditingNotification UITextFieldTextDidChangeNotification UITextFieldTextDidEndEditingNotification

UITableView

UITableViewSelectionDidChangeNotification UIApplicationDidFinishLaunchingNotification UIApplicationDidReceiveMemoryWarningNotification UIApplicationSignificantTimeChangeNotification UIApplicationWillResignActiveNotification UIApplicationWillTerminateNotification

UIApplication UIApplicationDidBecomeActiveNotification

Le dlgu est inform des vnements importants mais on voit galement que le mcanisme des notications le permet aussi tout objet dtre inform de ces vnements. Nous allons abonner le contrleur de vue principal de Convertisseur2 la notication UIApplicationWillTerminateNotification.

Programmer labonnement
Modiez la mthode initWithNibName: dans le chier MainViewController.m.
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil { if (self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]) { [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationWillTerminate:)

7.2. Utiliser les listes de proprits

263

name:UIApplicationWillTerminateNotification object:nil]; } return self; }

Nous indiquons au centre de notication par dfaut que nous souhaitons que le message applicationWillTerminate: soit transmis au contrleur de vue principal (addObserver:self), lorsque lapplication est sur le point de se terminer, quel que soit lobjet mettant cette notication (object:nil). Le contrleur de vue principal devient un observateur. Il ne faut pas oublier de supprimer lobservateur lorsquil est appel disparatre.
- (void)dealloc { [self viewDidUnload]; [[NSNotificationCenter defaultCenter] removeObserver:self]; [super dealloc]; }

Rception de la notication
Il suffit maintenant dajouter la dclaration de la mthode applicationWillTerminate: dans le chier MainViewController.h :
- (void)applicationWillTerminate: (NSNotification *)notification;

Dnissez ensuite cette mthode dans le chier MainViewController.m.


- (void)applicationWillTerminate: (NSNotification *)notification{ [self.convertisseur writeToFile:self.storeFile atomically:YES]; }

Linstance de la classe NSNotification qui est reue par cette mthode est un conteneur dont les proprits dcrivent la notication :
j j j

name est un NSString contenant le nom de la notication. object est lobjet qui a mis la notication. userInfo est un dictionnaire contenant des informations compl-

mentaires optionnelles.

7.3. Checklist
Nous avons explor deux techniques importantes mises en uvre pour la persistance des donnes :

264

7. Persistance des donnes

Core Data qui permet de raliser de petites bases de donnes :

les entits, attributs et relations ; les rgles dintgrit ; la pile Core Data, compose des units de stockage, du coordonnateur, du modle de donnes et du contexte.
j

les listes de proprits qui permettent la persistance de dictionnaires de donnes : le format XML utilis pour reprsenter un dictionnaire ; les types de donnes autoriss.

Nous avons galement avanc dans notre comprhension des vues en table et de la navigation par barre de navigation :
j j

le mode dition ; la classe NSFetchedResultsController qui facilite lutilisation de Core Data et son dlgu.

Nous avons vu les classes NSError, NSNumber et NSNotification et le motif notication/observation.

7.3. Checklist

265

DESSINS ET ANIMATIONS
Animer les images .................................................................................................... 269 Dessiner avec Quartz2D ......................................................................................... 282 Dbuter la 3D avec OpenGL ES .......................................................................... 290 Checklist ........................................................................................................................ 299

267

CHAPITRE 8

Nous en avons termin avec les interfaces utilisateur un peu tristes contenant des champs de texte et des boutons. Nous allons maintenant tirer parti des possibilits graphiques de liPhone, en particulier de ses capacits grer les animations. Nous apprendrons galement agrmenter nos applications avec des effets sonores.

8.1. Animer les images


Il existe deux techniques pour agrmenter son interface utilisateur avec des lments graphiques :
j

disposer dimages prpares, positionnes voire animes par le programme ; coder les instructions pour que le programme dessine.

Le plus simple et le plus efficace est de disposer dimages dj prtes, au format PNG ou JPEG. Nous avons dj appris positionner une image statique avec Interface Builder dans le chapitre consacr la prise en main du SDK. Nous nous attacherons ici aux deux techniques danimation utilises avec les images :
j j

animation du contenu de limage : les images animes ; dplacement dune image sur lcran.

Images animes
La technique danimation dune image est celle utilise dans les dessins anims : nous affichons une succession dimages un rythme rapide, par exemple 30 images par seconde, pour produire la sensation danimation. Nous supposerons donc que nous disposons dun ensemble dimages. Il nous reste voir comment utiliser cet ensemble dans une application iPhone.

Application Terre
Lobjet de lapplication Terre est de voir tourner le globe terrestre. La rotation complte du globe est dcompose en 44 images au format PNG disponibles dans les exemples complmentaires cet ouvrage. Vous pouvez aussi choisir votre propre squence dimages pour raliser cette application (voir Figure 8.1). Linterface utilisateur doit contenir une vue de type UIImageView dans laquelle sera effectue lanimation.

8.1. Animer les images

269

Figure 8.1 : Application Terre

Contrleur de vue
1 Sous XCode, crez une application de type View Based Application et nommez-la Terre. Ajoutez au projet les chiers dimages pour composer lanimation. 2 Modiez linterface de la classe TerreViewController pour y dclarer loutlet terre de type UIImageView*.
@interface TerreViewController : UIViewController { IBOutlet UIImageView *terre; } @property(nonatomic,retain) UIImageView *terre; @end

Nous allons maintenant crire le code pour charger les 44 images dans la vue terre puis dclencher lanimation. 3 Modiez la mthode viewDidLoad dans le chier TerreViewController.m. Noubliez pas denlever la mise en commentaire de cette mthode :
- (void)viewDidLoad { [super viewDidLoad]; NSMutableArray *images = [[NSMutableArray alloc] init]; for (int i=1;i<=44;i++) { UIImage *oneImage=[UIImage imageNamed:[NSString stringWithFormat:@"%d.png",i]]; [images addObject:oneImage]; }

270

8. Dessins et animations

terre.animationImages = [NSArray arrayWithArray:images]; [images release]; [terre startAnimating]; }

Les chiers images sont nomms 1.png, 2.png, etc. jusqu 44.png. La mthode contient donc une boucle pour composer le nom de chaque chier et lajouter dans le tableau modiable images. Ce tableau est ensuite converti en tableau immuable, pour amliorer les performances, avant dtre utilis pour initialiser la proprit animationImages de la vue terre. Enn, lanimation de cette vue est dclenche par lmission du message startAnimating.

Interface utilisateur
1 Ouvrez le chier TerreViewController.xib pour composer linterface utilisateur. Ajoutez une Vue Image (Image View) et liez-la avec loutlet terre du contrleur de vue. 2 Utilisez linspecteur dattributs pour dnir le mode de dessin de limage comme souhait. Vous pouvez faire glisser lune des images partir de la bibliothque media dans la vue image pour raliser des essais.

Figure 8.2 : Mode de dessin

Les modes les plus appropris sont gnralement les suivants :


j

Scale To Fill redimensionne limage qui sera insre pour quelle remplisse toute la vue. Aspect Fit redimensionne limage pour quelle prenne la place maximale sans que son aspect soit modi. Les zones ventuellement non occupes sont transparentes.

8.1. Animer les images

271

Aspect Fill redimensionne limage pour quelle occupe toute la vue sans que son aspect soit modi. Certaines parties de limage peuvent tre coupes. Center centre limage dans la vue sans la redimensionner.

Vous pouvez tester votre application.

Classe UIImage
Dans la mthode viewDidLoad, nous utilisons la mthode imageNamed: de la classe UIImage pour crer une image. Le paramtre de cette mthode est le nom dun chier, y compris lextension mais sans chemin daccs. Le chier est recherch dans les ressources de lapplication. Cette classe dispose aussi de la mthode imageWithContentsOfFile: qui joue le mme rle mais prend en paramtre le chemin daccs complet un chier. Ces deux mthodes retournent nil si le chier na pu tre trouv.

Challenge
Le code que nous avons crit fonctionne pour charger 44 images. Il serait plus facile den assurer la maintenance sil ne contenait pas cette information, sil fonctionnait quel que soit le nombre dimages insres dans les ressources de lapplication. Modiez la mthode viewDidLoad du contrleur de vue pour quelle ne dpende plus du nombre dimages lire.

Classe UIImageView
La cration dune animation tait trs simple : tout le travail est ralis par la classe UIImageView. Elle mrite quon la regarde plus attentivement ; les mthodes et proprits les plus utilises sont documentes dans le tableau.
Tableau 8.1 : Principales mthodes et proprits de la classe UIImageView Thme Signature Objet Initialise le rcepteur avec une image. Image contenue dans le rcepteur. Initialisation (id) initWithImage:

(UIImage *)image
Image

@property(nonatomic, retain) UIImage *image

272

8. Dessins et animations

Tableau 8.1 : Principales mthodes et proprits de la classe UIImageView Thme Animation Signature Objet Tableau dimages pour lanimation. Si cette proprit est initialise, la proprit image nest pas utilise. Dure dun cycle en secondes. Par dfaut, le cycle est calcul pour une vitesse daffichage de 30 images pas seconde. Nombre de cycles drouler avant larrt de lanimation. Par dfaut 0 ; lanimation ne sarrte pas seule. Dmarre lanimation. Stoppe lanimation. Retourne YES si lanimation est en cours.

@property(nonatomic, copy) NSArray *animationImages @property(nonatomic) NSTimeInterval animationDuration @property(nonatomic) NSInteger animation RepeatCount (void)startAnimating (void)stopAnimating (BOOL)isAnimating

Sonoriser une application


Pour donner encore plus de vie une application, on peut lui adjoindre des effets sonores. Nous allons ajouter un bruit dambiance sur la rotation du globe terrestre. 1 Ajoutez un chier au format MP3 ou au format WAV au projet Terre, par exemple ambiance.mp3. Ajoutez les lignes de code suivantes dans la mthode viewDidLoad du contrleur de vue :
NSError *error; player = [[AVAudioPlayer alloc] initWithContentsOfURL: [NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"ambiance" ofType:@"mp3" inDirectory:@"/"]] error:&error]; player.numberOfLoops = -1; [player prepareToPlay]; [player play];

2 Ajoutez une proprit TerreViewController.

AVAudioPlayer *player

la

classe

Nous avons cr un lecteur audio, une instance de la classe AVAudioPlayer. Nous lavons initialis avec le chier ambiance.mp3. Nous avons ensuite demand ce lecteur de prparer la restitution puis de lire le chier sonore. Les mthodes principales de cette classe sont :
j

initWithContentOfURL:error: pour initialiser le lecteur avec le contenu dune URL ;

8.1. Animer les images

273

j j j j

prepareToPlay pour prparer la restitution ; play pour commencer la lecture ; pause pour suspendre la lecture ; stop pour arrter la lecture.

3 Testez lapplication an de vrier que la terre tourne maintenant dans une belle ambiance sonore.

Format des sons


LiPhone sait lire plusieurs formats sonores mais les meilleures performances sont atteintes avec le format natif du processeur : PCM 16 bits sign, little endian, 44 100 Hz, encapsul dans un chier WAV ou AIF.

Dplacer une image


Intressons-nous maintenant la technique de base permettant de dplacer sur lcran un objet reprsent par une image. Cette dernire pourra ensuite tre enrichie pour animer plusieurs objets. Nous aborderons plus tard les techniques permettant de crer des images par programmation : Quartz2D puis OpenGL-ES. Nous illustrerons cette technique avec le dplacement dune boule sur une table de billard.

Dbuter lapplication
1 Crez une application Billard de type View Based Application. Ajoutez un outlet ball de type UIImageView* la classe BillardViewController :
@interface BillardViewController : UIViewController { IBOutlet UIImageView *ball; } @property(nonatomic,retain) UIImageView *ball; @end

2 Ajoutez aux ressources du projet un chier au format PNG ou JPEG contenant une image reprsentant la boule de billard. Leffet graphique sera optimal si le pourtour de la bille est transparent, limage doit contenir une couche Alpha (voir Figure 8.3).

274

8. Dessins et animations

Couche Alpha
Sur iPhone PS, les couleurs sont dnies par quatre composantes dont la valeur est comprise entre 0. et 1.0. Les trois premires dnissent lintensit des couleurs primaires, Rouge, Vert et Bleu, la quatrime est la valeur Alpha de la couleur qui en dnit le niveau de transparence ; 1.0 pour une couleur opaque et 0. pour une couleur totalement transparente.

Figure 8.3 : Effet de la transparence sur le pourtour de la bille

3 Ouvrez le chier BillardViewController.xib pour prparer linterface utilisateur : Modiez la couleur de fond de la vue principale pour obtenir un vert proche du feutre dune table de billard. Faites glisser limage de la boule de billard depuis la bibliothque media dInterface Builder sur la vue principale. Si vous souhaitez modier la taille de limage, choisissez le mode appropri, par exemple Aspect Fit. Connectez loutlet ball du propritaire du chier (Files owner) limage de la bille, en fait la vue image (Image View) contenant limage.

Se reprer dans une vue


Jusqu prsent, nous avons utilis Interface Builder pour disposer les diffrents lments de linterface utilisateur. Nous allons maintenant procder par programmation ; il faut donc comprendre comment est dnie la position dune vue sur lcran.

Un systme de coordonnes par vue


Dans la hirarchie des vues dont est compose linterface utilisateur, chaque vue dispose de son propre systme de coordonnes. Sur iPhone OS, lorigine par dfaut se situe en haut gauche de la vue, laxe des abscisses dle de gauche droite et laxe des ordonnes de haut en bas.

8.1. Animer les images

275

Figure 8.4 : Systme de coordonnes dune vue

Mac OS X et iPhone OS
Pour les habitus de la programmation sur Mac OS X, sur lequel lorigine des coordonnes se situe en bas gauche de la vue sous Cocoa, laxe des ordonnes est invers par rapport Cocoa Touch.

Frame et Bounds
La position dune vue incluse dans sa super-vue sappelle le cadre(frame) de la vue. Cest le rectangle, exprim dans le systme de coordonnes de la super-vue, dans lequel la vue est inscrite. Un rectangle est dni par :
j j

un point ; lorigine du rectangle ; une taille, cest--dire une largeur et une hauteur.

Taille "ngative"
La largeur ou la hauteur dun rectangle peuvent tre ngatives. Leur signe permet de dterminer la position de lorigine : par exemple, si elles sont

276

8. Dessins et animations

positives, lorigine du rectangle est son angle en haut gauche. Si elles sont toutes deux ngatives, lorigine est son angle en bas droite.

Une vue incluse peut elle-mme contenir dautres vues, il faut donc dnir son systme de coordonnes. Cela est fait indirectement en exprimant le cadre dans les coordonnes de la vue : les limites(bounds) de la vue. Par dfaut, le rectangle dni par les limites prsente la mme taille que le cadre et (0.,0.) pour origine. Le cadre et les limites sont un seul et mme rectangle, mais le cadre est exprim dans les coordonnes de la super-vue alors que les limites le sont dans les coordonnes de la vue incluse. Trois proprits de la classe UIView sont interdpendantes, frame (le cadre), bounds (les limites) et center (les coordonnes du centre de la vue incluse, exprimes dans les coordonnes de la super-vue) :
j

Lorsque frame est modie, center est recalcule et la taille de bounds prend la valeur de la taille de frame. Lorsque la taille de bounds est modie, elle est utilise ainsi que center pour recalculer frame. Lorsque center est modie, lorigine de frame est recalcule.

Types C pour les lments graphiques


Les proprits frame et bounds sont de type CGRect, La proprit center est de type CGPoint, deux structures C.
Tableau 8.2 : Principales structures C utilises pour les oprations graphiques Structure Composition Utilisation Origine du rectangle Taille du rectangle Abscisse du point Ordonne du point Largeur Hauteur

CGRect CGPoint CGSize

CGPoint origin CGSize size CGFloat x CGFloat y CGFloat width CGFloat height

Sagissant de structures C, leurs lments sont donc accessibles par la notation pointe, par exemple ball.center.x pour labscisse du centre de la boule et ball.center.y pour son ordonne.

8.1. Animer les images

277

CGFloat
Le type CGFloat est un synonyme de float dni dans le framework CoreGraphics. Nous avons dj rencontr des types spciques un framework, par exemple NSInteger. Cest une pratique qui permet damliorer la portabilit du code.

Les structures ne sont pas des classes


Les variables et proprits graphiques sont gnralement des structures, pas des rfrences, contrairement aux objets qui sont toujours des rfrences. En pratique, la dclaration des variables ne contient pas le caractre *. Ce sont des structures :

UIView * myView ; CGRect rect ;

// rfrence sur un objet // variable de type structure

Le framework CoreGraphics fournit plus de 30 fonctions pratiques pour manipuler ces structures gomtriques, par exemple :
j

des constructeurs :
CGPoint CGPointMake (CGFloat x,CGFloat y) ; CGSize CGSizeMake (CGFloat width,CGFloat height) ; CGRect CGRectMake (CGFloat x,CGFloat y,CGFloat width,CGFloat height).

des comparateurs :
bool CGRectContainsPoint (CGRect rect,CGPoint point) ; CGRect CGRectIntersection (CGRect r1,CGRect r2).

des calculs dinformations :


CGFloat CGRectGetMinX (CGRect rect) ; CGFloat CGRectGetMaxY (CGRect rect).

Vous trouverez la liste exhaustive de ces fonctions dans la documentation CGGeometry Reference.

Animer la boule de billard


Aprs cette introduction sur les concepts des coordonnes graphiques, revenons notre application Billard. Nous avons besoin de plusieurs lments pour animer la boule de billard :

278

8. Dessins et animations

j j j j

la valeur dun dplacement lmentaire ; une mthode qui ralise un dplacement lmentaire ; la frquence des dplacements lmentaires ; un moyen de squencer les dplacements lmentaires la bonne frquence.

1 Modiez le chier BillardViewController.h pour y ajouter la mthode moveBall qui ralisera un dplacement lmentaire et les variables dinstances qui contiendront la valeur dun dplacement lmentaire.
@interface BillardViewController : UIViewController { IBOutlet UIImageView *ball; CGFloat moveX; CGFloat moveY; } @property(nonatomic,retain) UIImageView *ball; - (void)moveBall; @end

2 Dans le chier BillardViewController.m, dnissez une constante timerInterval la valeur souhaite pour la frquence de rafrachissement, 1/30e de seconde :
#import "BillardViewController.h" const float timerInterval = 1./30.; @implementation BillardViewController

3 Modiez la mthode viewDidLoad pour initialiser la valeur du dplacement lmentaire et lancer le premier dplacement :
- (void)viewDidLoad { [super viewDidLoad]; moveX = 3.; moveY = -5.; [self moveBall]; }

4 crivez la mthode moveBall :


- (void) moveBall { CGPoint center = ball.center; center.x += moveX; center.y += moveY; ball.center = center; [self performSelector:@selector(moveBall) withObject:nil afterDelay:timerInterval]; }

Aprs avoir dplac la boule en modiant sa proprit center, nous armons un temporisateur qui va rmettre le message moveBall aprs une attente de timerInterval secondes. La mthode perform
8.1. Animer les images

279

Selector:withObject:afterDelay: est disponible pour tous les objets, quelle que soit leur classe. Son paramtre withObject: est utilis comme paramtre du message arm si le slecteur attend un paramtre.

5 Construisez lapplication et testez-la sur le simulateur. La boule se dplace correctement mais malheureusement, elle disparat rapidement. Nous allons maintenant implmenter les rebonds sur les bandes de la table de billard.

Dtecter les bandes


Dans les nombreux jeux que vous programmerez, il vous faudra surveiller les interactions entre diffrents objets. Le framework CoreGraphics propose la fonction CGRectIntersectsRect qui prend deux rectangles en paramtres et retourne YES si ces rectangles se recouvrent au moins en partie, et NO sils sont disjoints. Cette fonction est intressante pour dtecter si deux objets sont en contacts mais ne convient pas pour dtecter si la boule de billard est sur le point de "sortir" de la table. 1 Modiez la mthode moveBall pour dtecter si la boule sort de la table et ventuellement changer le dplacement lmentaire :
- (void) moveBall { // tableRect doit contenir les limites de lcran CGRect tableRect = self.view.bounds; // ballRect doit contenir le cadre de la boule CGRect ballRect = self.ball.frame; if (CGRectGetMinX(ballRect)<CGRectGetMinX(tableRect)|| CGRectGetMaxX(ballRect)>CGRectGetMaxX(tableRect)){ moveX = -moveX; } if (CGRectGetMinY(ballRect)<CGRectGetMinY(tableRect)|| CGRectGetMaxY(ballRect)>CGRectGetMaxY(tableRect)){ moveY = -moveY; } CGPoint center = ball.center; center.x += moveX; center.y += moveY; ball.center = center; [self performSelector:@selector(moveBall) withObject:nil afterDelay:timerInterval]; }

Nous navons pas utilis la fonction CGRectContainsRect qui teste si le second rectangle pass en paramtre est contenu en totalit dans le

280

8. Dessins et animations

premier car nous avons besoin de savoir si le dbordement est dans le sens horizontal ou vertical pour modier le dplacement lmentaire. 2 Reconstruisez et testez lapplication ; la boule rebondit maintenant sur les bandes. Essayez daugmenter le dplacement lmentaire pour acclrer le mouvement :
moveX = 15.; moveY = -12.;

Lanimation reste uide. Le framework CoreGraphics est optimis pour que le dplacement dune vue ne ncessite pas de redessiner cette vue ou celle situe en dessous : chaque vue possde son propre calque (layer).

Challenges
Challenge 1
Pour amliorer simplement le rendu du mouvement de la boule de billard, il faut modliser le frottement sur la table et la perte dnergie due aux chocs. Apportez cette amlioration dans la mthode moveBall. Vous pouvez adopter une perte de vitesse de 10 % chaque choc et de 0,5 % chaque dplacement lmentaire.

Challenge 2
Pour atteindre un rendu trs raliste, ajoutez lmission dun son chaque rebond de la boule sur une bande, comme nous lavons fait prcdemment dans ce chapitre. Seul le premier son est mis lorsque deux rebonds sont trop rapprochs. Une solution pour corriger ce problme consiste utiliser alternativement 2 lecteurs.

O trouver des sons


Outre les ressources, sons et images, qui vous sont proposes avec le code source accompagnant cet ouvrage, vous trouverez de nombreux effets sonores de bonne qualit sur le site http://www.soundsnap.com.

Challenge 3
Plus difficile, restructurez lapplication pour pouvoir positionner plusieurs boules sur la table. Il faut bien sr dtecter et traiter les collisions entre les boules.

8.1. Animer les images

281

Pour calculer les vitesses des deux boules aprs limpact, vous inspirez-vous du code C que vous trouverez sur le site http://fr.wikipedia .org/wiki/Choc_lastique.

8.2. Dessiner avec Quartz2D


Cette section est consacre aux moyens de composer et doptimiser le trac dun dessin pour conserver une bonne uidit des animations. An dillustrer ces techniques, nous visualiserons la trajectoire de la boule, pendant son dplacement, dans notre application Billard.

Figure 8.5 : Trac de la trajectoire

Principe de fonctionnement
Prcisions sur la classe UIView
Tous les objets qui saffichent lcran, les vues, drivent directement ou indirectement de la classe UIView. Elle a la responsabilit de grer :

282

8. Dessins et animations

j j j

la hirarchie des vues ; laffichage ; lanimation des vues.

La mthode drawRect: de la classe UIView dessine le contenu de la vue. Cette mthode est appele par le framework lorsque la vue est affiche la premire fois, puis lorsque son contenu volue. Si vous voulez personnaliser laspect graphique de vos applications, il vous faudra donc dnir votre propre classe drive de UIView, et coder le comportement graphique souhait dans la mthode drawRect:. Le paramtre pass cette mthode est le rectangle dans lequel le dessin doit tre excut. Par dfaut, le contenu de ce rectangle est effac avant lappel de drawRect:, son contenu doit alors tre compltement redessin par la mthode. La vue que vous dnissez devra vraisemblablement avoir un affichage variable, par exemple en fonction des valeurs des proprits. Lorsque laffichage doit voluer, il faut appeler lune des deux mthodes :
j j

setNeedsDisplay pour redessiner toute la vue. setNeedsDisplayInRect:. La partie redessiner est lintrieur du rectangle pass en paramtre qui sera retransmis drawRect:.

Ne pas appeler drawRect


Vous ne devez pas appeler la mthode drawRect: directement. Vous devez appeler lune des mthodes setNeedsDisplay ou setNeeds DisplayInRect: pour informer le framework quil doit appeler drawRect:.

Contexte graphique
Les fonctions permettant de dessiner sont regroupes dans le framework CoreGraphics. Elles prennent pratiquement toutes pour premier paramtre un pointeur sur le contexte graphique, leur permettant de savoir "o" dessiner. Lorsque la mthode drawRect: est appele, un contexte graphique adquat est initialis par dfaut, avec le systme de coordonnes dni par les limites de la vue. Gnralement, le code de la mthode drawRect: commence par lobtention du contexte graphique courant.
CGContextRef context = UIGraphicsGetCurrentContext();

8.2. Dessiner avec Quartz2D

283

Contexte graphique
Le contexte graphique permet de faire le lien entre les fonctions graphiques et la destination de limage. Que le dessin soit trac sur lcran ou dans un chier PDF, le dveloppeur utilise les mmes fonctions graphiques. Il na pas se proccuper de la destination de limage quil compose, cest le contexte graphique qui prend en charge les oprations dtailles.

Les fonctions graphiques sont des fonctions C


Pour des raisons de performances, les fonctions graphiques nont pas t dveloppes sous forme de classes Objective-C mais regroupes dans une bibliothque de fonctions C.

Mise en pratique
Avant daller plus loin, mettons en pratique ce que nous venons dapprendre : drawRect: et le contexte graphique. Nous allons raliser une classe drive de UIView pour effectuer le trac de la trajectoire de la boule de billard. Cette classe SnookerView comportera deux proprits qui permettront au contrleur de vue de lui transmettre les mouvements de la boule :
j

lastPoint, position nale de la boule, mise jour chaque mouvement lmentaire ; drawing, boolen indiquant si le trac doit tre ralis, indispensable pour commencer le dessin uniquement aprs avoir indiqu la position initiale de la boule.

Un trait doit tre dessin chaque mouvement lmentaire entre la dernire position de la boule et sa nouvelle position.

Crer la classe SnookerView


1 Sous XCode, crez les chiers sources .m et .h pour la classe SnookerView, en indiquant que cette classe hrite de UIView (voir Figure 8.6). 2 Modiez le chier SnookerView.h pour y dclarer les proprits de la nouvelle classe :

284

8. Dessins et animations

Figure 8.6 : Cration dune classe drive de UIView @interface SnookerView : UIView { BOOL drawing; CGPoint precedingLastPoint; CGPoint lastPoint; } @property(nonatomic,getter=isDrawing) BOOL drawing; @property(nonatomic) CGPoint lastPoint; @end

Nous dclarons :
j

une variable dinstance precedingLastPoint qui nest pas dnie comme une proprit ; nous aurons besoin de retenir la position prcdente de la boule pour effectuer le trac mais les utilisateurs de la classe SnookerView nont pas besoin dy accder ; un accesseur dnomm isDrawing plutt que drawing ; cest une pratique courante pour les proprits de type BOOL.

3 Ajoutez la dnition de la mthode setLastPoint: dans le chier SnookerView.m :


-(void)setLastPoint:(CGPoint)aPoint{ precedingLastPoint = lastPoint; lastPoint = aPoint; if (drawing) {

8.2. Dessiner avec Quartz2D

285

[self setNeedsDisplayInRect: CGRectMake(precedingLastPoint.x, precedingLastPoint.y, lastPoint.x-precedingLastPoint.x, lastPoint.y-precedingLastPoint.y)]; } }

Nous modions le manipulateur par dfaut de la proprit lastPoint car nous avons deux choses importantes faire lors de chaque modication de cette proprit :
j j

enregistrer la position prcdente de la boule ; informer le framework que cette vue doit tre redessine dans le rectangle dont une diagonale est dnie par le dernier point et le point prcdent.

Dessiner le trac
crivez le code de la mthode drawRect: :
- (void)drawRect:(CGRect)rect { CGContextRef context = UIGraphicsGetCurrentContext(); CGContextSetRGBStrokeColor(context, 1., 0.5, 0., 1.0); CGContextSetLineWidth(context, 3.); CGContextSetLineCap(context, kCGLineCapSquare); CGPoint segment[2] = {precedingLastPoint,self.lastPoint}; CGContextStrokeLineSegments(context, segment, 2); }

Nous reconnaissons la premire instruction qui permet dobtenir une rfrence au contexte graphique courant, vers lequel toutes les commandes graphiques seront transmises. Nous voulons que lappel de cette mthode provoque le trac dun trait entre le dernier point (proprit lastPoint) et le point prcdent (variable dinstance precedingLastPoint). Cela est accompli par lappel de la fonction CGContextStrokeLineSegments qui prend en paramtres un tableau de points et le nombre de points contenus dans le tableau. Cette fonction est utilisable pour tracer une succession de segments. Trois autres fonctions sont employes pour dnir les attributs graphiques du trait tracer :
j

CGContextSetRGBStrokeColor permet de dnir les composants Rouge, Vert, Bleu et Alpha de la couleur du trait. CGContextSetLineWidth permet de dnir la largeur du trait. CGContextSetLineCap permet de dnir le trac de lextrmit des segments. Le paramtre de cette fonction est une constante.

j j

286

8. Dessins et animations

Tableau 8.3 : Paramtres de la fonction CGContextSetLineCap Forme de terminaison Paramtre utiliser Commentaire Le trait est arrt lextrmit du segment. Le trait est arrondi autour de lextrmit du segment.

kCGLineCapButt kCGLineCapRound

kCGLineCapSquare Le trait est carr autour de lextrmit du


segment.

Il existe dautres fonctions graphiques mais nous vous demandons un peu de patience. Il nous reste utiliser notre nouvelle classe dans le contrleur de vue pour terminer lapplication.

Utiliser la nouvelle classe


Modier le chier NIB
An dutiliser les proprits et les mthodes que nous venons de dnir, il faut modier la classe de la vue dans le chier NIB. 1 Ouvrez le chier BillardViewController.xib dans Interface Builder. 2 Slectionnez la vue principale et indiquez quelle doit tre de la classe SnookerView dans linspecteur didentit (X+[4]).

Figure 8.7 : La vue principale doit appartenir la classe SnookerView

8.2. Dessiner avec Quartz2D

287

Modier le contrleur de vue


1 Modiez la mthode viewDidLoad dans le chier BillardViewController.m pour initialiser le trac du dplacement :
- (void)viewDidLoad { [super viewDidLoad]; moveX = 15.; moveY = -12.; [(SnookerView *)self.view setLastPoint: ball.center]; [(SnookerView *)self.view setDrawing:YES]; [self moveBall]; }

cast (SnookerView *)
La proprit view est dclare comme une UIView dans la classe UIViewController, et ne dispose pas des proprits lastPoint et drawing. Nous employons donc linstruction de changement de type (cast) (SnookerView *) pour viter un message davertissement la compilation.

2 Modiez la mthode moveBall pour raliser le trac de la trajectoire chaque dplacement lmentaire :
- (void) moveBall { CGRect tableRect = self.view.bounds; CGRect ballRect = self.ball.frame; if (CGRectGetMinX(ballRect)<CGRectGetMinX(tableRect)|| CGRectGetMaxX(ballRect)>CGRectGetMaxX(tableRect)){ moveX = -moveX; } if (CGRectGetMinY(ballRect)<CGRectGetMinY(tableRect)|| CGRectGetMaxY(ballRect)>CGRectGetMaxY(tableRect)){ moveY = -moveY; } CGPoint center = ball.center; center.x += moveX; center.y += moveY; ball.center = center; [(SnookerView*)self.view setLastPoint: center]; [self performSelector:@selector(moveBall) withObject:nil afterDelay:timerInterval]; }

3 Reconstruisez lapplication et vriez que la trajectoire est dessine correctement. Cette application dmontre deux caractristiques importantes du framework CoreGraphics pour loptimisation du dessin et des animations :

288

8. Dessins et animations

Seul le contenu du rectangle pass en paramtre la mthode


drawRect: doit tre redessin.

Chaque vue tant dessine dans son propre calque, la boule se superpose au trac de la trajectoire. Elle apparat bien au-dessus de la table et il nest pas ncessaire de redessiner ce qui tait sous la boule lorsque celle-ci se dplace.

Primitives graphiques
Les principales primitives graphiques sont rsumes dans le tableau ci-aprs.
Tableau 8.4 : Principales primitives graphiques Thme Signature Objet Retourne le contexte graphique par dfaut. Contexte Graphique CGContextRef

UIGraphicsGet CurrentContext (void)


Attributs graphiques void CGContextSet

LineCap ( CGContextRef c, CGLineCap cap) void CGContextSet LineWidth ( CGContextRef c, CGFloat width) void CGContextSet RGBFillColor ( CGContextRef c, CGFloat red, CGFloat green, CGFloat blue, CGFloat alpha) void CGContextSet RGBStrokeColor ( CGContextRef c, CGFloat red, CGFloat green, CGFloat blue, CGFloat alpha)

Dnit le type de terminaison du trac des segments de droite.

Dnit la largeur du trac des segments de droite.

Dnit les composantes de la couleur de remplissage pour les formes gomtriques.

Dnit les composantes de la couleur de trac.

8.2. Dessiner avec Quartz2D

289

Tableau 8.4 : Principales primitives graphiques Thme Signature Objet Peint le contenu du rectangle pass en paramtre avec la couleur de remplissage pralablement dnie. Peint le contenu de lellipse dnie par le rectangle pass en paramtre avec la couleur de remplissage pralablement dnie. Trace le contour du rectangle pass en paramtre avec la couleur de trac pralablement dnie. Trace le contour de lellipse dnie par le rectangle pass en paramtre avec la couleur de trac pralablement dnie. Fonctions de dessin void CGContext

FillRect ( CGContextRef c, CGRect rect) void CGContext FillEllipseInRect ( CGContextRefcontext, CGRect rect) void CGContext StrokeRect ( CGContextRef c, CGRect rect) void CGContext StrokeEllipseInRect ( CGContextRefcontext, CGRect rect)

void CGContext Trace la suite de segments dont les StrokeLineSegments ( points sont dans le tableau pass en CGContextRef c, paramtres. const CGPointpoints[], size_t count)

Nhsitez pas consulter la documentation Apple et essayer les nombreuses fonctions graphiques. Le framework Core Graphics est trs riche et permet notamment de :
j

tracer des arcs, des courbes de Bzier, des motifs et des lignes discontinues ; dnir des dgrads de couleurs, des ombres ; raliser des rotations ou dautres transformations ; dessiner du texte, etc.

j j j

8.3. Dbuter la 3D avec OpenGL ES


Le graphisme en trois dimensions permet de reprsenter des scnes trs ralistes : ombres portes, textures, sources de lumire, brillance, etc. Malheureusement, ce rsultat est obtenu au prix dune grande complexit ; le livre OpenGL superbible dit par Addison Wesley compte 1 200 pages. Nous allons limiter notre ambition dans cette section qui est destine ceux dentre vous qui connaissent dj OpenGL ES et souhaitent savoir comment le mettre en uvre sur iPhone OS :

290

8. Dessins et animations

prsenter OpenGL ES utilis sur iPhone OS pour le graphisme en trois dimensions ; expliquer comment cette bibliothque standard est exploite dans une application Cocoa Touch.

Figure 8.8 : Exemple de graphisme 3D

Prsentation dOpenGLES
OpenGL est une bibliothque graphique (Graphics Library) standard accessible en langage C, donc en Objective-C. Elle est largement utilise dans nombre dapplications professionnelles ou ludiques. OpenGL ES est une version allge dOpenGL conue pour les appareils mobiles (Embedded Systems).

OpenGL ES existe en deux versions, prises en charge sur iPhone OS. Le dveloppeur choisira celle quil souhaite utiliser :
j

la version 1.1 est une bibliothque classique de primitives graphiques. la version 2.0 permet de programmer des fonctions qui sexcutent directement sur le processeur graphique.

La documentation de rfrence officielle, en anglais, se trouve sur les sites suivants :


j j

http://www.khronos.org/opengles/sdk/1.1/docs/man/ pour la version 1.1 ; http://www.khronos.org/opengles/sdk/docs/man/ pour la version 2.0.

Intgration dans Cocoa Touch


Lutilisation dOpenGL ES ncessite de la part du dveloppeur un effort supplmentaire. Non seulement il faut connatre la bibliothque et les principes du graphisme 3D, mais il faut aussi comprendre comment OpenGL ES et Core Animation travaillent ensemble.

8.3. Dbuter la 3D avec OpenGL ES

291

Il ny a pas dans Cocoa Touch, contrairement Cocoa sur Mac OS X, dobjet de type Vue prt lemploi pour utiliser OpenGL ES. Il nous faudra driver une classe dUIView, appelons-la EAGLView, pour nous conformer au modle dapplication propos par XCode.

Frameworks
Pour utiliser OpenGLES dans un projet sous XCode, il faut y ajouter les frameworks QuartzCore et OpenGLES. Slectionnez la cible (target) du projet puis activez la commande Existing Framework du sous-menu Add du menu contextuel.

Modle OpenGL ES
Les frameworks ncessaires sont inclus dans le modle de projet OpenGL ES Application sous XCode.

Les dclarations importer sont les suivantes :


#import #import #import #import #import #import #import <QuartzCore/QuartzCore.h> <OpenGLES/ES1/gl.h> <OpenGLES/ES1/glext.h> <OpenGLES/ES2/gl.h> <OpenGLES/ES2/glext.h> <OpenGLES/EAGL.h> <OpenGLES/EAGLDrawable.h> // // // // pour pour pour pour OpenGL OpenGL OpenGL OpenGL ES ES ES ES 1.1 1.1 2.0 2.0

Calque OpenGL ES
Nous savons dj que chaque instance de la classe UIView, ou dune classe drive, possde son propre calque. Il est accessible via la proprit layer de type CALayer*. La vue et le calque associ tant intimement lis, la classe UIView dnit une mthode +layerClass qui retourne la classe utiliser comme calque. Cette classe doit driver de CALayer qui est le dfaut. Pour utiliser la bibliothque OpenGL ES, il faut utiliser un calque de la classe CAEAGLLayer. Notre classe EAGLView devra donc modier la mthode +layerClass de la classe UIView :
+ (Class) layerClass { return [CAEAGLLayer class]; }

Contexte graphique
Les primitives graphiques dOpenGL ES, comme celles de Core Graphics, sont diriges vers un contexte graphique. Dans le cas

292

8. Dessins et animations

dOpenGL ES, le contexte graphique doit tre une instance de la classe EAGLContext cre linitialisation de la vue :
context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES1];

Le contexte est cr soit avec la constante kEAGLRendering APIOpenGLES1, soit avec la constante kEAGLRenderingAPIOpenGLES2 suivant que lon veut travailler en version 1.1 ou en version 2.0. Le contexte auquel toutes les commandes graphiques doivent tre transmises est ensuite spci par linstruction :
[EAGLContext setCurrentContext:context];

Zones tampons
Lorsque lapplication compose une image, elle ne travaille pas directement sur lcran. Elle utilise des zones tampons (buffers) spciques, suivant le type dinformations (couleur, profondeur, pochoir) qui servent composer limage, lies entre elles dans un cadre tampon (framebuffer). Une fois limage compose, elle est transmise en une fois sur lcran. Chaque tampon est repr par un identicateur qui est un nombre entier. Les tampons sont gnralement crs linitialisation de la vue.

Crer le cadre tampon


Sous OpenGL ES v1.1, le cadre tampon est cr puis li au contexte graphique par la suite dinstructions :
GLuint framebuffer; glGenFramebuffersOES(1, &framebuffer); glBindFramebufferOES(GL_FRAMEBUFFER_OES, framebuffer);

La fonction glGenFrameBuffersOES est employe ici pour crer un seul cadre tampon. Elle prend deux paramtres :
j j

le nombre de cadres tampons crer ; un tableau dentiers dans lequel les identiants des cadres crs seront rangs.

La fonction glBindFramebufferOES est utilise pour lier le cadre tampon nouvellement cr au contexte courant, an den faire la destination des commandes graphiques venir.

Extension OES
Les fonctions de gestion des zones tampons et du cadre tampon sont dnies dans la version 2.0 dOpenGL ES. Sous iPhone OS, on utilise le mme

8.3. Dbuter la 3D avec OpenGL ES

293

systme de fonctions avec la version 1.1. Les noms de ces fonctions se terminent dans ce cas par OES, nom de lextension Apple OpenGL ES 1.1. partir de cette section, les exemples seront donns en version 1.1. Il sera facile den dduire lutilisation en version 2.0 en enlevant les caractres OES la n des fonctions et constantes.

Le cadre tampon est susceptible de regrouper :


j

Une zone tampon pour les couleurs (color buffer) dans laquelle seront calcules les couleurs de limage dessiner. Cette zone tampon est obligatoire. Une zone tampon pour la profondeur (depth buffer) permettant de dterminer les parties caches de limage. Cette zone tampon nest pas utilise pour les images en deux dimensions. Optionnellement, une zone tampon pour les pochoirs (stencil buffer) ou une zone tampon pour les textures (texture buffer).

Crer la zone tampon des couleurs


Sous OpenGL ES v1.1, la zone tampon des couleurs est cre puis lie au contexte graphique par la suite dinstructions :
GLuint colorRenderbuffer; glGenRenderbuffersOES(1, &colorRenderbuffer); glBindRenderbufferOES(GL_RENDERBUFFER_OES, colorRenderbuffer); glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES,GL_RENDERBUFFER_OES, colorRenderbuffer);

La fonction glFramebufferRenderbufferOES permet dattacher une zone tampon un cadre tampon. Le deuxime paramtre permet de spcier le type dattachement :
j j j

GL_COLOR_ATTACHMENT0_OES pour la zone tampon des couleurs ; GL_DEPTH_ATTACHMENT_OES pour la zone tampon de profondeur ; GL_STENCIL_ATTACHMENT_OES pour la zone tampon des pochoirs.

Les autres zones tampons ventuellement ncessaires sont cres et attaches de la mme faon.

Dnir le port OpenGL


Le port OpenGL (view port) est la zone sur lcran dans laquelle doivent tre effectus les tracs graphiques. Il doit donc tre li la vue EAGLView et plus prcisment son calque. Mais auparavant, il

294

8. Dessins et animations

faut le dimensionner, ce qui ne peut tre fait quaprs que la vue soit concrtement dispose sur lcran. Cest pourquoi les instructions suivantes sont gnralement places dans la mthode layoutSubviews de la classe EAGLView :
GLint viewWidth, viewHeight; [context renderbufferStorage:GL_RENDERBUFFER_OES fromDrawable:self.layer]; glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_WIDTH_OES, &viewWidth); glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_HEIGHT_OES, &viewHeight); glViewport(0, 0, viewWidth, viewHeight);

Le contexte graphique est dabord attach au calque de la vue ; il en prend donc les dimensions. Puis ces dimensions sont rcupres pour dnir le systme de coordonnes du port OpenGL.

Utiliser le contexte graphique


Lorsque toutes les zones tampons ont t cres et attaches au cadre tampon, on peut tester la bonne conguration de ce dernier, par exemple de la faon suivante :
if (glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES) != GL_FRAMEBUFFER_COMPLETE_OES) { NSLog(@"Echec lors de la cration du cadre tampon %x", glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES)); return; }

Le contexte graphique est enn prt pour recevoir les instructions de dessin. Lorsque limage est prte, elle peut tre affiche lcran :
[context presentRenderbuffer:GL_RENDERBUFFER_OES];

Lorsque limage a t transmise lcran, le tampon des couleurs est rinitialis. Dans le cas dune animation, il faut recomposer compltement limage aprs laffichage de chaque trame.

Exemple dapplication
An dillustrer les concepts que nous venons de voir, nous allons analyser un exemple dapplication : le modle OpenGL ES Application propos par XCode. Sous XCode, crez un projet de type OpenGL ES Application. Construisez lapplication et testez-la sur le simulateur ; un carr rempli par un dgrad de couleurs se balance doucement. Vous pouvez crer une application pour iPhone ou pour iPad ; elles fonctionnent de la mme faon.

8.3. Dbuter la 3D avec OpenGL ES

295

Structure des classes


Examinez les chiers du groupe Classes, le modle propos par XCode contient :
j j j j

une classe pour le dlgu dapplication ; une classe EAGLView, qui drive de UIView ; deux classes ES1Renderer et ES2Renderer ; un protocole ESRenderer.

Ce modle ne contient pas de contrleur de vue spcique, cest le dlgu dapplication qui gre la vue directement : il a une proprit glView et contrle le fonctionnement de lanimation. Les applications OpenGL ES ne respectent pas le modle MVC. Laspect graphique est rparti en trois classes :
j j j

ES1Renderer contient les instructions spciques OpenGL ES 1.1. ES2Renderer contient les instructions spciques OpenGL ES 2.0. EAGLView contient le code indpendant de la version utilise et le mcanisme daiguillage entre les deux versions dOpenGL ES.

Le protocole ESRenderer permet au code dEAGLView de fonctionner indiffremment avec lune des classes ES1Renderer ou ES2Renderer. Cest dans lune des classes ES1Renderer ou ES2Renderer, suivant que vous adoptez la version 1.1 ou la version 2.0, que vous devez mettre votre code OpenGL ES, plus particulirement dans la mthode render. Ouvrez le chier ES1Renderer.m et vriez que vous localisez les instructions de paramtrage du contexte graphique et des zones tampons vus dans les sections prcdentes. Nous allons nous concentrer sur la classe EAGLView qui offre quelques particularits que nous navons pas encore vues.

Classe EAGLView
La classe EAGLView prend en charge :
j

La conguration du calque (layer). En particulier, elle implmente la mthode +layerClass pour indiquer quil faut utiliser un calque OpenGL ES. Le pilotage de lanimation. Le choix de la version dOpenGL ES, en loccurrence 1.1 uniquement si la version 2.0 ne fonctionne pas sur lappareil.

j j

296

8. Dessins et animations

Linterface avec les deux mthodes du protocole ESRenderer.


resizeFromLayer: pour naliser linitialisation du contexte graphique lorsque la dimension dnitive de la vue est connue ; render pour dessiner limage.

Pilotage de lanimation
Ouvrez le chier EAGLView.m pour tudier la mthode employe pour rythmer lanimation.
- (void) startAnimation { if (!animating) { if (displayLinkSupported) { displayLink = [NSClassFromString(@"CADisplayLink") displayLinkWithTarget:self selector:@selector(drawView:)]; [displayLink setFrameInterval:animationFrameInterval]; [displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; } else animationTimer = [NSTimer scheduledTimerWithTimeInterval: (NSTimeInterval)((1.0 / 60.0) * animationFrameInterval) target:self selector:@selector(drawView:) userInfo:nil repeats:TRUE]; animating = TRUE; } }

Nous voyons que lune des deux classes suivantes est utilise :
j j

CADisplayLink ;

ou NSTimer, le temporisateur universel.

Lavantage de CADisplayLink sur NSTimer est que le temps ncessaire pour calculer une nouvelle image est pris en compte an de xer le rythme de rafrachissement ; cest la classe favoriser pour synchroniser une animation. Elle nest malheureusement disponible qu partir de la version 3.1 de liPhone OS, cest pourquoi la classe EAGLView possde une proprit displayLinkSupported qui est value dans la mthode initWithCoder: :
displayLinkSupported = FALSE; NSString *reqSysVer = @"3.1"; NSString *currSysVer =

8.3. Dbuter la 3D avec OpenGL ES

297

[[UIDevice currentDevice] systemVersion]; if ([currSysVer compare:reqSysVer options:NSNumericSearch] != NSOrderedAscending) displayLinkSupported = TRUE;

NSClassFromString
Dans le code de la mthode startAnimation, Il faut utiliser lappel de fonction NSClassFromString(@"CADisplayLink") plutt que simplement la classe CADisplayLink pour viter les erreurs la construction de lapplication si lon emploie un SDK qui ne contient pas cette classe.

Classe UIDevice
Nous avons vu prcdemment un exemple de quelques instructions permettant de connatre les caractristiques de lappareil sur lequel lapplication sexcute. Le tableau ci-aprs rsume quelques-unes des proprits des instances de la classe UIDevice.
Tableau 8.5 : Principales proprits de la classe UIDevice Thme Obtenir linstance courante Signature Objet Retourne linstance reprsentant lappareil sur lequel lapplication sexcute. Identiant unique de lappareil (UDID)

+ (UIDevice *)current Device

Identier lappareil et @property (nonatomic, le systme dexploita- readonly, retain) NSString tion

*uniqueIdentifier @property (nonatomic, readonly, retain) NSString *name @property (nonatomic, readonly, retain) NSString *systemVersion @property (nonatomic, readonly, retain) NSString *model
Nom de lappareil

Version du systme dexploitation

Modle dappareil, actuellement retourne @"iPhone", @"iPod touch", @"iPad", @"iPhone Simulator" ou @"iPad Simulator". Niveau de charge de la batterie. Retourne une valeur comprise entre 0 (0 %) et 1 (100 % de charge).

tat de la batterie

@property (nonatomic, readonly) float batteryLevel

298

8. Dessins et animations

8.4. Checklist
Ce chapitre nous a permis dexplorer quelques-unes des possibilits graphiques et danimation diPhone OS :
j j j

animation dune image, avec les classes UIImageView et UIImage ; dplacement dune image sur lcran ; primitives graphiques de Quartz2D : le cadre (frame), les limites (bounds) et les diffrents systmes de coordonnes ; les types de donnes CGRect, CGPoint et CGSize ; la mthode drawRect:.

intgration de la bibliothque OpenGL ES pour le graphisme en trois dimensions : lexistence des deux versions 1.1 et 2.0 ; le paramtrage du contexte graphique ; les zones tampons et le cadre tampon.

Nous avons agrment nos applications avec des effets sonores laide de la classe AVAudioPlayer et vu comment les animer avec la mthode performSelector:withObject:afterDelay: ou la classe CADisplayLink. Nous avons galement expos la classe UIDevice qui permet de connatre les caractristiques de lappareil courant.

8.4. Checklist

299

TAPES, TOUCHES ET GESTES


Comprendre les vnements ............................................................................... 303 Traiter les vnements ............................................................................................ 307 Mettre en uvre les gestes .................................................................................. 313 Checklist ........................................................................................................................ 320

301

CHAPITRE 9

Nous avons dcouvert le mcanisme cible-action au chapitre 2. Il nous a permis de raliser des applications qui ragissent aux actions de lutilisateur :
j j j

dition dun champ de texte ; appui sur un bouton ; changement de valeur dun slectionneur.

LiPhone OS nous permet aussi de proposer lutilisateur une interface labore avec des gestes complexes, un ou plusieurs doigts. Leur mise en uvre dans une application ncessite davancer dans notre comprhension des vnements (events) grs par Cocoa Touch. Nous commencerons par explorer les classes et techniques de base mises en jeu puis dvelopperons quelques applications mettant en uvre les gestes courants sur iPhone OS.

Gestes sous iPhone OS 3.2


La version 3.2 diPhone OS, disponible sur iPad, permet une mise en uvre simplie des gestes standard (pincement, dplacement, glissement, etc.) par le mcanisme cible-action. Cette mise en uvre sera dtaille dans le chapitre consacr aux spcicits de liPad. Ce chapitre concerne donc principalement le dveloppement sur iPhone et iPod Touch. Il est destin galement ceux qui souhaitent dvelopper leur propre analyseur de geste pour iPad.

9.1. Comprendre les vnements


Classe UIResponder
Le mcanisme cible-action est mis en uvre par les objets de la classe UIControl qui drive indirectement de la classe UIResponder avec laquelle nous avons fait connaissance au chapitre 4. (voir Figure 9.1) Lorsquun vnement survient, lapplication plus prcisment linstance unique de la classe UIApplication recherche le rpondeur (une instance de la classe UIResponder) appropri et lui transmet lvnement :
j

Si lvnement est une action sur lcran, le rpondeur est la vue situe sous le doigt de lutilisateur.

9.1. Comprendre les vnements

303

Figure 9.1 : Classes gestionnaires des vnements

Dans le cas contraire, lvnement est transmis au premier rpondeur (First responder) puis remonte la chane des rpondeurs jusqu ce que lun deux accepte de le traiter. Si le rpondeur est un contrle (une instance de la classe UIControl), lvnement est susceptible dtre utilis pour dclencher le mcanisme cible-action. Nous allons nous intresser ici la faon dont les vnements sont reus par un rpondeur pour dnir nos propres comportements dans des vues ou des contrleurs spciques.
j

vnements lmentaires
Les vnements reus par un rpondeur peuvent tre de deux sortes reprsentes par le type numr UIEventType :
j j

UIEventTypeTouches pour les touches sur lcran ; UIEventTypeMotion pour les mouvements de lappareil.

Le type numr UIEventSubtype est galement dni. Dans la version actuelle, les sous-types concernent uniquement les mouvements de lappareil :
j j

UIEventSubtypeNone, pas de sous-type particulier ; UIEventSubtypeMotionShake, mouvement de secousse de lappareil (shake).

Les vnements concernant les touches sont plus complexes ; chaque touche lmentaire peut tre :
j

la pose du doigt sur lcran ;

304

9. Tapes, touches et gestes

j j

le dplacement du doigt sur lcran ; le retrait du doigt de lcran.

Touche
Une touche est un vnement lmentaire concernant seulement un doigt : pose du doigt sur lcran, dplacement du doigt sur lcran ou retrait du doigt de lcran.

En outre, pour dcrire la touche lmentaire, il faut galement prciser :


j

La position de la touche. Cocoa Touch fournit un point dans les coordonnes de la vue concerne, bien que la taille dun doigt normal recouvre plusieurs points lorsquil touche lcran. Le moment prcis auquel lvnement est intervenu. Il est donn par le nombre de secondes coules depuis le dmarrage de lappareil.

Un petit point pour un gros doigt


La zone touche par un doigt sur lcran est gnralement de forme ellipsodale, de taille variable en fonction du doigt et de la pression exerce. Le systme Multi-Touch analyse cette information pour calculer un point unique associ la touche.

Toutes ces informations sont prsentes dans une instance de la classe UITouch dcrite dans le tableau ci-aprs.
Tableau 9.1 : Mthodes et proprits de la classe UITouch Thme Emplacement des touches Signature Objet

(CGPoint)location Retourne lemplacement de la touche dans InView:(UIView *)view le systme de coordonnes de la vue passe en paramtre, ou dans le systme de coordonnes de la fentre si nil est pass en paramtre.

(CGPoint)previous LocationInView: (UIView *)view

Retourne lemplacement prcdent de la touche dans le systme de coordonnes de la vue passe en paramtre, ou dans le systme de coordonnes de la fentre si nil est pass en paramtre. La vue dans laquelle la touche a dbut.

@property(nonatomic, readonly, retain) UIView *view @property(nonatomic, readonly, retain) UIWindow *window

La fentre dans laquelle la touche a dbut.

9.1. Comprendre les vnements

305

Tableau 9.1 : Mthodes et proprits de la classe UITouch Thme Attributs de la touche Signature Objet Le nombre de tapes effectues par lutilisateur. Lhorodate de la dernire modication de la touche. La phase dans laquelle se trouve la touche : UITouchPhaseBegan lorsque le doigt vient de toucher lcran ; UITouchPhaseMoved lorsque le doigt vient de se dplacer ; UITouchPhaseStationary lorsque le doigt na pas boug depuis le dernier vnement ; UITouchPhaseEnded lorsque le doigt vient de se retirer de lcran ; UITouchPhaseCancelled si lvnement a t interrompu.

@property(nonatomic, readonly) NSUInteger tapCount @property(nonatomic, readonly) NSTime Interval timestamp @property(nonatomic, readonly) UITouch Phase phase

Remarquez la proprit phase qui permet de dterminer la touche lmentaire reprsente : pose, dplacement ou retrait du doigt. Cette proprit peut galement indiquer :
j j

si le doigt est immobile sur lcran ; si lvnement a t interrompu (cancelled) ; cest le cas par exemple si liPhone reoit un appel pendant lutilisation dune application.

cran Multi-Touch
La technologie Multi-Touch permet au systme de suivre les mouvements simultans de plusieurs doigts sur lcran. Chaque mouvement est dcompos en une srie de touches lmentaires. Les touches lmentaires simultanes sont regroupes au sein dun mme vnement, une instance de la classe UIEvent. Il appartient au rpondeur dinterprter ces suites dvnements pour dterminer les gestes effectus par lutilisateur. Par exemple, un pincement (pinch) est dcompos de la faon suivante : j Deux doigts sont poss simultanment sur lcran.
j j

La distance entre les deux doigts diminue. Les deux doigts sont retirs de lcran.

Chacun de ces trois vnements est compos de deux touches lmentaires : deux poss, deux dplacements et deux retraits.
306
9. Tapes, touches et gestes

Les classes drives de UIView ou de UIControl doivent implmenter le code ncessaire pour interprter les gestes qui leur sont propres : glissement (swipe), pichenette (ick), pincement (pinch), etc. Nous allons examiner les mthodes utiliser pour implmenter vos propres gestes dans vos classes drives.

9.2. Traiter les vnements


Recevoir les vnements
Classe UIEvent
Une instance de la classe UIEvent reprsente un vnement ; cest sous cette forme quil est transmis au rpondeur. Elle peut contenir une ou plusieurs touches, sous la forme dinstances de UITouch, ou reprsenter une secousse de lappareil. Les mthodes et proprits de la classe UIEvent sont dcrites dans le tableau ci-aprs.
Tableau 9.2 : Mthodes et proprits de la classe UIEvent Thme Obtenir les touches Signature Objet ment.

(NSSet *)allTouches Retourne toutes les touches de lvne (NSSet *)touches ForView:(UIView *)view (NSSet *)touches ForWindow:(UIWindow *)window property(nonatomic, readonly) NSTime Interval timestamp @property(readonly) UIEventType type
Retourne les touches appartenant une vue. Retourne les touches appartenant une fentre. Lhorodate de lvnement en secondes depuis le dmarrage du systme. Le type est soit

Obtenir les attributs de lvnement Type dvnement

UIEventTypeTouches pour un ensemble de touches, soit UIEventTypeMotion pour un mouvement de lappareil.


Le sous-type est

@property(readonly) UIEventSubtype subtype

UIEventSubtypeNone si lvnement na pas de sous-type particulier ou UIEventSubtypeMotionShake


pour une secousse de lappareil.

Les touches de lvnement sont retournes dans une instance de la classe NSSet. Il sagit dun conteneur, au mme titre que NSArray et
9.2. Traiter les vnements

307

NSDictionary que nous connaissons dj, qui reprsente un ensemble. Les lments dun ensemble ne sont pas rangs de faon particulire et son contenu est explor avec linstruction for :
NSSet * aSet = [NSSet setWithObjects:@"Jean",@"Marc", @"Paul",nil]; for ( NSString * name in aSet) { // name contiendra successivement Jean, Marc et Paul }

Deux autres mthodes de la classe NSSet sont utiles pour traiter les vnements :
j j

(id)anyObject qui retourne un lment quelconque du conteneur ; (NSArray*)allObjects qui retourne un tableau contenant tous les objets du conteneur.

Conditions de rception
vnements de touches
Pour des raisons de performance, les vnements de touches ne sont transmis par lapplication quaux vues qui satisfont certains critres :
j

La vue doit tre affiche lcran.

Figure 9.2 : Cases cocher pour recevoir les vnements de touches 308
9. Tapes, touches et gestes

La vue doit contenir le point touch par lutilisateur, sauf si sa proprit exclusiveTouch vaut YES, auquel cas la vue recevra tous les vnements de la fentre. La proprit userInteractionEnabled de la vue doit valoir YES ou la case User Interaction Enabled doit tre coche dans linspecteur des attributs de la vue sous Interface Builder. Une vue ne peut recevoir quune touche la fois, sauf si sa proprit multipleTouchEnabled vaut YES ou si la case Multiple Touch est coche.

vnements de mouvements
Les vnements de mouvements sont transmis par lapplication au premier rpondeur (First Responder). Un rpondeur devient le premier rpondeur lorsque :
j j

Il reoit le message becomeFirstResponder. Uniquement si sa mthode canBecomeFirstResponder retourne YES.

Par dfaut, la mthode canBecomeFirstResponder retourne NO. Il faut donc rednir cette mthode si lon veut que nos propres classes drives de UIResponder puissent devenir des premiers rpondeurs :
- (BOOL)canBecomeFirstResponder{ return YES; }

Pour quune vue puisse devenir premier rpondeur, il faut galement quelle soit affiche lcran. De la mme faon, pour quun contrleur de vue puisse devenir premier rpondeur, sa vue doit tre affiche lcran. Il ne faut donc pas appeler la mthode becomeFirstResponder tant que cette condition nest pas remplie ; la mthode viewDidAppear de UIViewController constitue une bonne opportunit pour dnir le premier rpondeur :
- (void)viewDidAppear:(BOOL)animated { [self becomeFirstResponder]; }

signaler aussi la possibilit de bloquer temporairement le traitement des vnements par lapplication :
UIApplication * appli = [UIApplication sharedApplication]; [appli beginIgnoringInteractionEvents]; // plus aucun vnement nest trait par lapplication [appli endIgnoringInteractionEvents]; // les vnements sont de nouveau traits par lapplication

9.2. Traiter les vnements

309

Notication dvnements
Nous avons compris ce quest un vnement, une touche, et quelles sont les conditions pour que les vnements arrivent au rpondeur. Intressons-nous maintenant la faon dont un rpondeur reoit les vnements et la faon dont il doit les traiter.

Mouvements
La secousse de lappareil est le seul mouvement qui provoque un vnement dans la version actuelle diPhone OS.

Secouer le Simulateur
Vous pouvez simuler une secousse sur le Simulateur diPhone avec la commande Secousse du menu Matriel ([Ctrl]+X+[Z])

Lorsquun tel vnement se produit, le premier rpondeur reoit les messages suivants :
j

(void)motionBegan:(UIEventSubtype)motion withEvent:(UIEvent *)event lorsquun mouvement dbute ; (void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event lorsque le mouvement se termine ; (void)motionCancelled:(UIEventSubtype)motion withEvent:(UIEvent *) event lorsque le mouvement est interrompu.

En pratique, les paramtres motion et event ne sont pas utiliss, puisquun seul type dvnement peut survenir, et le code qui permet lapplication de ragir laction de lutilisateur est plac dans la mthode motionEnded:withEvent: :
- (void)motionBegan:(UIEventSubtype)motion withEvent:(UIEvent *)event { } - (void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event { // Insrer ici le code pour traiter lvnement } - (void)motionCancelled:(UIEventSubtype)motion withEvent:(UIEvent *)event { }

310

9. Tapes, touches et gestes

Dfinir toutes les mthodes


Si votre rpondeur drive de UIView ou UIViewController, ce qui est le cas le plus courant, les trois mthodes prcdemment dcrites doivent tre rednies mme si certaines dentre elles ne contiennent pas de code.

Challenge
Compltez lapplication Billard du chapitre prcdent : la vitesse de la boule doit tre rinitialise lorsque lutilisateur secoue lappareil. Indications :
j

Implmentez les mthodes de traitement des vnements dans le contrleur de vue BillardViewController. Noubliez pas de dnir ce contrleur de vue comme premier rpondeur.

Touches
Les vnements de touches lmentaires sont transmis aux rpondeurs par les messages suivants :
j

(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event pour les touches qui dbutent (qui correspondent une pose de doigt) ; (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event pour les touches qui correspondent un dplacement ; (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event pour les touches qui se terminent (retrait du doigt) ; (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event pour les touches interrompues.

Le paramtre touches de chacune de ces mthodes contient les touches lmentaires, instances de la classe UITouch, qui sont respectivement dans les tats UITouchPhaseBegan, UITouchPhaseMoved, UITouchPhaseEnded et UITouchPhaseCancelled. Le paramtre event regroupe toutes les touches lmentaires de lvnement, quel que soit leur tat. Nous mettrons en uvre ces mthodes dans la section suivante.

Librer les ressources


Les ressources ventuellement alloues pour grer un geste doivent tre libres lorsque le geste se termine, cest--dire dans la mthode

9.2. Traiter les vnements

311

touchesEnded:withEvent: sil sagit de lvnement qui clt le geste, et dans la mthode touchesCancelled:withEvent: lorsque le geste est interompu.

Dfinir toutes les mthodes


Comme dans le cas des vnements de mouvement, si votre rpondeur drive de UIView ou UIViewController, les quatre mthodes prcdemment dcrites doivent tre rednies mme si certaines dentre elles ne contiennent pas de code.

Tapes multiples
La classe UITouch dnit une proprit tapCount ; un entier contenant le nombre de tapes effectues au mme endroit. Pour savoir si une touche est une tape multiple, il suffit de tester cette proprit dans la mthode touchesEnded:withEvent:. Il y a un petit dtail auquel il faut faire attention si nous souhaitons obtenir un comportement diffrent pour chaque tape. Notre rpondeur va recevoir une premire srie dvnements la premire tape, une autre srie la deuxime, etc. Lorsque la premire tape est reue, nous devons attendre une fraction de secondes avant de dclencher laction attendue an de dterminer sil sagit dune tape simple, double, etc. Le plus simple pour arriver ce rsultat est de lancer laction dclenche par une tape simple avec la mthode performSelector: withObject:afterDelay: :
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { UITouch *theTouch = [touches anyObject]; if (theTouch.tapCount == 1) { [self performSelector:@selector(handleSingleTap) withObject:nil afterDelay:0.3]; } else if (theTouch.tapCount == 2) { // Instructions pour traiter une tape double } } - (void) handleSingleTap { // Instructions pour traiter une tape unique }

312

9. Tapes, touches et gestes

Ceci nous laissera lopportunit dannuler cette action sil savre que la premire tape tait le dbut dune tape double :
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { UITouch *aTouch = [touches anyObject]; if (aTouch.tapCount == 2) { [NSObject cancelPreviousPerformRequestsWithTarget:self]; } }

On peut utiliser le mme mcanisme pour discriminer les tapes triples, quadruples, etc. La multiplicit des tapes nest pas limite par Cocoa Touch.

9.3. Mettre en uvre les gestes


Il est temps de mettre en uvre les lments que nous venons de voir en ralisant des vues qui ragissent aux gestes de lutilisateur. Nous allons enrichir notre application Billard en donnant la possibilit lutilisateur de propulser la boule par une chiquenaude. Nous illustrerons ensuite les touches multiples par la mise en uvre du pincement.

Chiquenaude
Comportement souhait
Physique de la chiquenaude
La chiquenaude est un dplacement dun doigt sur lcran qui doit :
j j

tre rapide ; sil est trop lent, il ne doit pas tre pris en compte ;
percuter la boule ; le mouvement doit passer proximit du centre

de la boule, il faut prendre en compte limprcision due la taille du doigt. Nous allons mettre des hypothses simplicatrices quant leffet de la chiquenaude sur la boule :
j

La boule est propulse la vitesse de la chiquenaude ; la vitesse de dplacement du doigt sur lcran. La boule est propulse dans la direction de la chiquenaude ; il ny a pas deffet de rotation de la boule due une percussion qui ne serait pas radiale.

9.3. Mettre en uvre les gestes

313

Mathmatique de la chiquenaude
Une chiquenaude se traduira par une srie dvnements de dplacement dune touche lmentaire. Chaque dplacement peut tre considr sparment, nous navons besoin de conserver que lhorodate (timestamp) de la dernire touche lmentaire pour calculer la vitesse de dplacement lors de lvnement suivant. Nous utiliserons les mthodes previousLocationInView: et location InView: de UITouch pour dterminer les caractristiques de la chiquenaude :
j j

Le dplacement rencontre-t-il la boule ? Quel est le vecteur vitesse donner la boule ?

Rpondre la premire question requiert un niveau de mathmatique lmentaire. Si ce nest pas votre cas, nous vous demandons de nous faire conance. Si le dernier dplacement lmentaire va du point 1 au point 2, nous considrons les deux vecteurs :
j j

celui qui va du point 1 au point 2 ; celui qui va du point 1 la position de la boule.

Figure 9.3 : Le dplacement rencontre-t-il la boule ?

On considrera que la boule est percute si :


j

le premier vecteur est plus long que le second, au diamtre de la boule prs ; langle entre les deux vecteurs est suffisamment petit. Cet angle sera indirectement valu laide du dterminant des deux vecteurs.

314

9. Tapes, touches et gestes

Classe SnookerView
Le travail de cette classe est de dtecter la chiquenaude et den transmettre les paramtres au contrleur de vue :
j j

un rectangle dni par les deux points du dplacement ; la dure du dplacement du doigt entre ces deux points.

Pour transmettre ces informations, nous allons dnir un protocole de dlgu spcique auquel le contrleur de vue devra se conformer. 1 Ouvrez le projet Billard sous XCode et modiez le chier SnookerView.h, nous en protons pour dnir une variable dinstance lastTime qui nous servira calculer la dure du dplacement :
@protocol SnookerViewDelegate; @interface SnookerView : UIView { BOOL drawing; CGPoint precedingLastPoint; CGPoint lastPoint; NSTimeInterval lastTime; IBOutlet id <SnookerViewDelegate> delegate; } @property(nonatomic,getter=isDrawing) BOOL drawing; @property(nonatomic) CGPoint lastPoint; @property(nonatomic,assign) id <SnookerViewDelegate> delegate; @end @protocol SnookerViewDelegate <NSObject> @optional - (void)swipeMove:(CGRect)move withDuration:(NSTimeInterval)swipeDuration; @end

2 Modiez le dbut du chier SnookerView.m pour synthtiser les accesseurs de la proprit delegate et la vitesse minimale dune chiquenaude :
const float minSpeed = 300.; @implementation SnookerView @synthesize drawing,lastPoint,delegate;

3 Ajoutez les mthodes permettant de traiter les vnements de touches :


- (void)touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event{ lastTime = [[touches anyObject] timestamp]; } - (void)touchesMoved:(NSSet*)touches

9.3. Mettre en uvre les gestes

315

withEvent:(UIEvent*)event{ UITouch * touch = [touches anyObject]; NSTimeInterval currentTime = [touch timestamp]; NSTimeInterval swipeDuration = currentTime-lastTime; lastTime = currentTime; CGPoint point1 = [touch previousLocationInView:self]; CGPoint point2 = [touch locationInView:self]; CGRect move = CGRectMake(point1.x, point1.y, point2.x-point1.x, point2.y-point1.y); CGFloat speed = sqrt(move.size.width*move.size.width + move.size.height*move.size.height)/swipeDuration; if (speed > minSpeed) { if ([self.delegate respondsToSelector: @selector(swipeMove:withDuration:)]) { [self.delegate swipeMove:move withDuration:swipeDuration]; } } } - (void)touchesEnded:(NSSet*)touches withEvent:(UIEvent*)event{ } - (void)touchesCancelled:(NSSet*)touches withEvent:(UIEvent*)event{ }

Classe BillardViewController
Le travail du contrleur est de vrier si la chiquenaude doit avoir un effet sur la boule, et le cas chant de raliser cet effet. Tout cela sera effectu dans la mthode swipeMove:withDuration: dnie dans le protocole SnookerViewDelegate. 1 Ajoutez cette mthode dans le chier BillardViewController.m :
- (void)swipeMove:(CGRect)move withDuration:(NSTimeInterval)swipeDuration { // Dtermination de la proximit de la boule // longueur de la chiquenaude CGFloat moveLength = sqrt(move.size.width*move.size.width+ move.size.height*move.size.height); // Vecteur Origine-Boule et longueur CGSize ballVector = CGSizeMake(ball.center.x-move.origin.x, ball.center.y-move.origin.y); CGFloat ballLength = sqrt(ballVector.width*ballVector.width+ ballVector.height*ballVector.height); // calcul du dterminant CGFloat det = (move.size.width*ballVector.heightmove.size.height*ballVector.width)/(moveLength*ballLength); // Modification de la vitesse de la boule 316
9. Tapes, touches et gestes

if ((ballLength<moveLength+distancePrecision)&& (fabs(det)<anglePrecision)){ moveX = move.size.width*timerInterval/swipeDuration; moveY = move.size.height*timerInterval/swipeDuration; // effacement de la table [(SnookerView*)self.view setDrawing:NO]; [self.view setNeedsDisplay]; // premier dplacement [(SnookerView*)self.view setLastPoint: ball.center]; [(SnookerView*)self.view setDrawing:YES]; [self moveBall]; } }

2 Dclarez les constantes ncessaires en tte du chier :


const float distancePrecision = 15.; const float anglePrecision = 0.1;

3 Noubliez pas de dclarer que la classe BillardViewController adopte le protocole SnookerViewDelegate dans son chier dinterface puis ouvrez le chier BillardViewController.xib sous Interface Builder pour attacher le dlgu de la vue SnookerView au propritaire du chier. 4 Cochez la case Clear Context Before Drawing dans linspecteur des attributs pour la vue SnookerView dans le chier NIB. Vous pouvez construire lapplication et la tester.

Challenge
Vous aurez certainement remarqu que lon peut devenir trs violent avec la boule, et lui donner une vitesse faramineuse au point quelle peut sortir de lcran. Limitez la vitesse de la boule ou amliorez le code pour que la boule ne sorte jamais de lcran.

Pincement
Le deuxime exemple de geste que nous allons dvelopper est le pincement tel quil est utilis dans Safari pour iPhone et qui a particip la popularit de liPhone. Un pincement est un geste dans lequel deux doigts sont poss sur lcran et scartent ou se rapprochent. Nous allons crer une vue qui dtecte ce geste en vriant, lors dun dplacement dune touche lmentaire, que deux touches sont en cours dutilisation.

9.3. Mettre en uvre les gestes

317

Si cest le cas, le ratio (distance actuelle entre les deux touches)/ (distance prcdente entre les deux touches) sera transmis au dlgu de la vue.

Classe PinchView
1 Crez un nouveau projet sous XCode de type View Based Application. Intitulez-le Pinch. Crez une nouvelle classe PinchView qui drive de UIView. Ajoutez la dnition du protocole de dlgu de cette classe dans son chier dinterface :
#import <UIKit/UIKit.h> @protocol PinchViewDelegate; @interface PinchView : UIView { id <PinchViewDelegate> delegate; } @property(nonatomic,retain) id delegate; @end @protocol PinchViewDelegate @required - (void) pinchPerformed:(float) ratio; @end

2 Ajoutez les mthodes de traitement des vnements de touche dans le chier PinchView.m :
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { } - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event { if ([[event touchesForView:self] count]==2) { // 2 doigts sont poss sur lcran NSArray *t=[[event touchesForView:self] allObjects]; // t1 et t2 sont les deux touches sur lcran UITouch *t1 = [t objectAtIndex:0]; UITouch *t2 = [t objectAtIndex:1]; // calcul de la distance prcdente CGPoint p1 = [t1 previousLocationInView:self]; CGPoint p2 = [t2 previousLocationInView:self]; CGFloat previousDistance = sqrt((p1.x-p2.x)*(p1.x-p2.x)+(p1.y-p2.y)*(p1.y-p2.y)); // calcul de la distance actuelle p1 = [t1 locationInView:self]; p2 = [t2 locationInView:self]; CGFloat currentDistance = sqrt((p1.x-p2.x)*(p1.x-p2.x)+(p1.y-p2.y)*(p1.y-p2.y)); // transmission du ratio au dlgu [delegate pinchPerformed: currentDistance/previousDistance];

318

9. Tapes, touches et gestes

} } - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { } - (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event { }

On dnombre toutes les touches prsentes sur lcran ([event touchesForView:self]) et pas seulement celles qui viennent de se dplacer (touches).

Classe PinchViewController
1 Modiez linterface du contrleur de vue pour quil adopte le protocole de dlgu de PinchView. Nous y ajoutons un champ de texte qui nous permettra de visualiser leffet des pincements :
#import <UIKit/UIKit.h> #import "PinchView.h" @interface PinchViewController : UIViewController <PinchViewDelegate>{ IBOutlet UILabel *label; } @property(nonatomic,retain) UILabel *label; @end

2 Dans le chier PinchViewController.m, synthtisez les accesseurs pour la proprit label et ajoutez la mthode pinchPerformed: :
- (void)pinchPerformed:(float)ratio{ float previousValue = [label.text floatValue]; label.text = [NSString stringWithFormat:@"%f", previousValue*ratio]; }

Finaliser lapplication
Pour naliser lapplication : 1 Ouvrez le chier PinchViewController.xib sous Interface Builder. 2 Dnissez la classe de la vue principale ; PinchView. 3 Autorisez les touches multiples dans la vue principale. 4 Dnissez le propritaire du chier NIB comme dlgu de la vue principale. 5 Ajoutez un label sur la vue principale. Initialisez-le 100. 6 Liez ce label loutlet label du propritaire du chier. Vous pouvez maintenant construire et tester lapplication.

9.3. Mettre en uvre les gestes

319

Pincement sur le simulateur


Le pincement est le seul geste plusieurs doigts ralisable sur le simulateur diPhone. Pressez la touche z sur le clavier en manipulant la souris.

9.4. Checklist
Ce chapitre nous a permis de connatre les diffrents types dvnements lmentaires de Cocoa Touch :
j j

secousse de lappareil ; touches lmentaires et leurs diffrents stades permettant dinterprter les gestes effectus par lutilisateur :

Un doigt se pose sur lcran. Un doigt se dplace. Un doigt est retir de lcran. Nous avons ensuite compris comment sont reprsents ces vnements par des instances des classes UIEvent et UITouch, puis comment ils sont reus et traits par les rpondeurs de la classe UIResponder. Ces principes ont t illustrs par limplmentation de deux gestes courant, la chiquenaude et le pincement.

320

9. Tapes, touches et gestes

APPAREIL PHOTO

Slectionner une photo .......................................................................................... 323 Prendre des photos .................................................................................................. 331 Enregistrer ses photos ............................................................................................ 332 diter les photos ........................................................................................................ 336 Envoyer ses photos .................................................................................................. 336 Checklist ........................................................................................................................ 339

321

CHAPITRE 10

Nous allons amliorer notre application Emprunts2 qui deviendra Emprunts3. Notre objectif maintenant est de conserver une preuve du prt ; nous allons crer une fonctionnalit permettant dajouter une photo chaque enregistrement. Certains exemples fournis dans ce chapitre fonctionnent uniquement sur iPhone. Il ny a actuellement pas dappareil photo sur iPod Touch ni sur iPad.

10.1. Slectionner une photo


Nous allons commencer par dcouvrir la classe UIImagePicker Controller et son utilisation dans notre application Emprunts pour slectionner une photo parmi les albums de lapplication Photos.

Figure 10.1 : Interface pour choisir une photo

Codage de linterface
Sous XCode, crez un projet Emprunts3 partir du projet Emprunts2.

Interface de la classe
1 Sous XCode modiez le chier LendObjectViewController.h pour y ajouter :

10.1. Slectionner une photo

323

un outlet imageView de classe UIImageView an de visualiser une miniature de la photo choisie ; une variable dinstance picture de classe UIImage qui contiendra la photo choisie ; un outlet pictureButton de classe UIButton pour rgler le comportement du bouton ; une action takePicture qui sera active lorsque lutilisateur souhaitera choisir une image :
@interface LendObjectViewController : UIViewController <UINavigationControllerDelegate, UIImagePickerControllerDelegate>{ NSManagedObject * lendObject; IBOutlet UITextField * objectNameField; IBOutlet UITextField * borrowerNameField; IBOutlet UIImageView * imageView; IBOutlet UIButton * pictureButton; IBOutlet UIDatePicker * datePicker; UIImage * picture; } @property(nonatomic,retain) NSManagedObject * lendObject; @property(nonatomic,retain) UITextField * objectNameField; @property(nonatomic,retain) UITextField * borrowerNameField; @property(nonatomic,retain) UIImageView * imageView; @property(nonatomic,retain) UIButton * pictureButton; @property(nonatomic,retain) UIDatePicker * datePicker; @property(nonatomic,retain) UIImage * picture; - (IBAction) doneEditing:(id)sender; - (IBAction) deleteObject; - (IBAction) takePicture; @end

Nous dclarons aussi que notre classe LendObjectViewController adopte les protocoles UINavigationControllerDelegate et UIImage PickerControllerDelegate. 2 Enregistrez le chier LendObjectViewController.h.

Interface utilisateur
1 Ouvrez le chier LendObjectViewController.xib sous Interface Builder pour y ajouter une vue image et un bouton. 2 Liez la vue image loutlet imageView, le bouton loutlet pictureButton et lvnement Touch Up Inside du bouton laction takePicture du propritaire du chier.

324

10. Appareil photo

Codage du contrleur de vue


Le contrleur de vue LendObjectViewController doit raliser plusieurs tches :
j j

vrier que des albums photos sont disponibles sur lappareil ; lancer le slectionneur de photo lorsque lutilisateur a touch le bouton adquat ; prendre en compte la photo choisie ; afficher une miniature de la photo choisie.

j j

Vrier que les albums photos sont disponibles


Sous XCode, ouvrez le chier LendObjectViewController.m et modiez la mthode viewDidLoad :
- (void)viewDidLoad { [super viewDidLoad]; UIBarButtonItem *cancelButton = [[UIBarButtonItem alloc] initWithTitle:@"Delete" style:UIBarButtonItemStyleDone target:self action:@selector(deleteObject)]; self.navigationItem.rightBarButtonItem = cancelButton; [cancelButton release]; if ([UIImagePickerController isSourceTypeAvailable: UIImagePickerControllerSourceTypePhotoLibrary]){ [pictureButton setTitle:@"Choisir une photo" forState:UIControlStateNormal]; } else { pictureButton.enabled = NO; } }

Le chargement de la vue est le bon endroit pour dnir le titre du bouton ou le dsactiver si lalbum photo nest pas disponible sur lappareil. Nous utilisons la classe UIImagePickerController qui permet de grer toutes les sources de photos de lappareil. Sa mthode +isSourceTypeAvailable: renvoie YES si la source dont lidentiant est pass en paramtre est disponible sur lappareil. Les types de source existants sont :
j

UIImagePickerControllerSourceTypePhotoLibrary pour accder aux albums de la bibliothque de lapplication Photos ; UIImagePickerControllerSourceTypeCamera pour accder la camra vido ou lappareil photo ;

10.1. Slectionner une photo

325

UIImagePickerControllerSourceTypeSavedPhotosAlbum pour accder aux vidos ou photos enregistres depuis la camra ou lappareil photo, ou par dfaut aux albums de la bibliothque de lapplication Photos.

Lancer le slectionneur de photos


Ajoutez le code de laction takePicture :
- (void) takePicture { UIImagePickerController *picker = [[UIImagePickerController alloc] init]; picker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary; picker.delegate = self; [self presentModalViewController:picker animated:YES]; [picker release]; }

Nous crons un contrleur spcique pour la slection dune photo, une instance de la classe UIImagePickerController puis nous lui indiquons que nous souhaitons explorer les albums photo. Enn, nous activons le contrleur.

Prendre en compte le choix dimage


Nous allons maintenant coder les deux mthodes du protocole UIImagePickerControllerDelegate, lune qui est appele lorsque lutilisateur a slectionn une image, et lautre lorsquil annule lopration :
- (void)imagePickerController:(UIImagePickerController *) picker didFinishPickingMediaWithInfo:(NSDictionary *)info{ self.picture = [info objectForKey:UIImagePickerControllerOriginalImage]; [self dismissModalViewControllerAnimated:YES]; } - (void)imagePickerControllerDidCancel: (UIImagePickerController *)picker { [self dismissModalViewControllerAnimated:YES]; }

Le paramtre info de la mthode imagePickerController:didFinish PickingMediaWithInfo: est un dictionnaire qui contient les informations relatives au mdia slectionn (photo ou vido). La cl UIImagePickerControllerOriginalImage permet de rcuprer la photo slectionne. Comme pour les vues modales standard, il est de la responsabilit du dlgu de dsactiver la vue modale en appelant la mthode dismissModalViewControllerAnimated:.

326

10. Appareil photo

Afficher la photo
Pour afficher la photo slectionne, il suffit de complter la mthode viewWillAppear: qui est appele juste avant que la vue soit affiche :
- (void)viewWillAppear:(BOOL)animated{ if ( [self.lendObject valueForKey: @"lendDate"] ) { self.objectNameField.text = [self.lendObject valueForKey: @"objectName"] ; self.borrowerNameField.text = [self.lendObject valueForKey: @"borrowerName"] ; self.datePicker.date = [self.lendObject valueForKey: @"lendDate"] ; } self.imageView.image = self.picture; [super viewWillAppear:animated]; }

Finaliser lapplication
1 Synthtisez les accesseurs pour les trois proprits que nous venons de dclarer : imageView, pictureButton et picture :
@synthesize imageView, pictureButton, picture;

2 Librez les proprits retenues :


- (void)viewDidUnload { self.objectNameField = nil; self.borrowerNameField = nil; self.datePicker = nil; self.imageView = nil; self.pictureButton = nil; } - (void)dealloc { [self viewDidUnload]; self.lendObject = nil; self.picture = nil; [super dealloc]; }

Libration des proprits


Nous librons les proprits. Celles qui sont dnies dans le chier NIB, les outlets, et celles qui sont alloues dans la mthode viewDidLoad doivent tre libres dans la mthode viewDidUnload. Les autres sont libres dans la mthode dealloc.

Le slectionneur dimage tant susceptible dutiliser beaucoup de ressources, il nest pas impossible que la mthode viewDidUnload soit appele sur linstance de LendObjectViewController pendant que

10.1. Slectionner une photo

327

lutilisateur choisit une photo. Il est donc important de librer tous les outlets car ils seront tous recrs lorsque ce contrleur reprendra la main sur linterface utilisateur. Il est important aussi de ne pas librer les rfrences vers le modle, en loccurrence les proprits lendObject et picture, car le contrleur ne saura pas les recrer seul. 3 Construisez lapplication et testez-la. ce stade, le test peut tre effectu sur le simulateur. Cest bien de pouvoir choisir une photo. Ce serait encore mieux si ce choix pouvait tre conserv avec la liste des objets prts. Avant de nous occuper de cela, nous allons faire plus ample connaissance avec la classe UIImagePickerController et son protocole de dlgu.

Classe UIImagePickerController
Le tableau rsume les mthodes et proprits de la classe UIImagePickerController.
Tableau 10.1 : Mthodes et proprits de la classe UIImagePickerController Thme Signature Objet Retourne un tableau contenant la Sources des images + (NSArray *) available

MediaTypesForSourceType: liste des types de mdias disponi(UIImagePickerController ble dans le type de source pass SourceType)sourceType en paramtre. En particulier kUTTypeMovie si lappareil est
capable denregistrer de la vido.

+ (BOOL) isSourceType Available: (UIImage PickerController SourceType)sourceType @property(nonatomic) UIImagePickerController SourceType sourceType
Congurer le slectionneur

Retourne YES si la source est disponible sur lappareil.

Source utilise pour la slection dimages. Doit tre initialis avant dactiver le contrleur. Doit tre initialis YES pour autoriser ldition par lutilisateur de limage ou de la vido slectionne. Vaut NO par dfaut. Dlgu.

@property(nonatomic) BOOL allowsEditing

@property(nonatomic, assign) id <UINavigation ControllerDelegate, UIImagePickerController Delegate> delegate

@property(nonatomic,copy) Tableau contenant les mdias dont NSArray *mediaTypes laccs est autoris. kUTTypeImage par dfaut

328

10. Appareil photo

Tableau 10.1 : Mthodes et proprits de la classe UIImagePickerController Thme Conguration de la prise de vido Signature Objet Niveau de qualit slectionne. Mdium par dfaut. Dure maximale de la capture vido. La valeur par dfaut est de 10 minutes, ce qui est la valeur maximale admissible.

@property(nonatomic) UIImagePickerController QualityType videoQuality @property(nonatomic) NSTimeInterval videoMaximumDuration

Commandes de la prise de vue

@property(nonatomic)BOOL YES pour que les commandes showsCameraControls par dfaut soient affiches. @property(nonatomic, retain) UIView *cameraOverlayView @property(nonatomic) CGAffineTransform cameraViewTransform (void) takePicture
Vue contenant des commandes personnalises. nil par dfaut. Transformation appliquer sur limage pendant la prise de vue. Utilis dans un contrle personnalis pour prendre une photo.

On voit que cette classe peut tre utilise aussi bien pour mettre en uvre la camra de lappareil, prendre une photo ou capturer une vido. Nous ajouterons cette fonctionnalit lapplication Emprunts3. Cette classe permet galement au dveloppeur dajouter ses propres contrles pendant la prise de vue et dactiver le module lmentaire ddition dimage. La proprit videoQuality est du type numr UIImagePicker ControllerQualityType qui peut prendre lune des trois valeurs suivantes :
j j

UIImagePickerControllerQualityTypeHigh pour une qualit haute ; UIImagePickerControllerQualityTypeMedium pour une qualit moyenne ; ou UIImagePickerControllerQualityTypeLow pour une qualit mdiocre.

Type de mdia
Seule la camra de liPhone 3GS peut capturer de la vido, liPod Touch ne dispose pas de camra et la date o nous crivons ces lignes, liPad nen dispose pas non plus.

10.1. Slectionner une photo

329

Utilisez les mthodes isSourceTypeAvailable: et availableMedia TypesForSourceType: pour connatre les caractristiques de lappareil sur lequel votre application sexcute.

Protocole UIImagePickerControllerDelegate
Le tableau rsume les deux mthodes dnies dans le protocole UIImagePickerControllerDelegate, nous les avons dj utilis toutes les deux.
Tableau 10.2 : Mthodes du protocole UIImagePickerControllerDelegate Mthode Objet Le slectionneur pass en paramtre vient de slectionner une image. Les informations sont dans le dictionnaire pass en second paramtre. Le slectionneur pass en paramtre vient dtre annul par lutilisateur.

(void) imagePickerController: (UIImagePickerController *)picker didFinishPickingMediaWithInfo: (NSDictionary *)info (void) imagePickerController DidCancel:(UIImagePicker Controller *)picker

Le dictionnaire info reu par la mthode imagePickerController: didFinishPickingMediaWithInfo: est susceptible de contenir les informations suivantes :
j

le type de mdia captur, sous la cl UIImagePickerController MediaType ; kUTTypeImage pour une image et kUTTypeMovie pour une vido ; limage originale, sous la cl UIImagePickerControllerOriginalImage, de type UIImage ; limage ventuellement modie par lutilisateur lors de la prise de vue, sous la cl UIImagePickerControllerEditedImage ; de type UIImage ; le rectangle dlimitant la partie de limage slectionne par lutilisateur, sous la cl UIImagePickerControllerCropRect ; de type CGRect ; ladresse URL de la vido capture, sous la cl UIImagePicker
ControllerMediaURL ; de type NSURL.

330

10. Appareil photo

10.2. Prendre des photos


Ce serait sans doute plus pratique pour lutilisateur, sil pouvait prendre une photo directement depuis lapplication Emprunts3. La classe UIImagePickerController le permet, mais comme certains appareils (iPod Touch et iPad) ne sont pas dots dun appareil photo, il faut que linterface utilisateur sadapte la situation.

Adapter linterface utilisateur


Modiez la mthode viewDidLoad de la classe LendObjectViewController pour y adapter le titre du bouton en fonction des capacits de lappareil :
- (void)viewDidLoad { [super viewDidLoad]; UIBarButtonItem *cancelButton = [[UIBarButtonItem alloc] initWithTitle:@"Delete" style:UIBarButtonItemStyleDone target:self action:@selector(deleteObject)]; self.navigationItem.rightBarButtonItem = cancelButton; [cancelButton release]; if ([UIImagePickerController isSourceTypeAvailable: UIImagePickerControllerSourceTypeCamera]){ [pictureButton setTitle:@"Prendre une photo" forState:UIControlStateNormal]; } else if ([UIImagePickerController isSourceTypeAvailable: UIImagePickerControllerSourceTypePhotoLibrary]){ [pictureButton setTitle:@"Choisir une photo" forState:UIControlStateNormal]; } else { pictureButton.enabled = NO; } }

Adapter le slectionneur de photos


1 Modiez la mthode takePicture de la classe LendObjectView Controller pour indiquer au slectionneur de photo quelle source utiliser en fonction des capacits de lappareil :
- (void) takePicture { UIImagePickerController *picker = [[UIImagePickerController alloc] init]; if ([UIImagePickerController isSourceTypeAvailable: UIImagePickerControllerSourceTypeCamera]){ picker.sourceType = UIImagePickerControllerSourceTypeCamera;

10.2. Prendre des photos

331

} else { picker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary; } picker.delegate = self; [self presentModalViewController:picker animated:YES]; [picker release]; }

2 Reconstruisez et testez lapplication. Testez-la successivement avec le simulateur et sur un iPhone ou sur un iPod Touch pour vrier quelle sadapte aux capacits de lappareil.

10.3. Enregistrer ses photos


Pour que lapplication Emprunts3 soit utile, il faut que la photo prise par lutilisateur soit range avec les donnes de lobjet prt, dans la structure Core Data. Nous allons raliser cette fonction.

Grer une image sous Core Data


Dclarer une image dans le modle de donnes
ditez le chier Emprunts3.xcdatamodel sous XCode. Ajoutez une proprit image, de type Binary data, dans lentit LendObject.

Figure 10.2 : Proprit image de LendObject

Outre les types dattribut prdnis que nous connaissons dj (nombre, chane de caractres, boolen, et date), le type Binary Data permet de stocker tout autre type de donnes dans une structure Core Data, en particulier une image de type UIImage comme nous le verrons bientt. Le type dattribut Binary Data est quivalent la classe Objective-C NSData qui encapsule un tableau doctets. Et comme toute donne informatique nest au nal quun tableau doctets, on peut utiliser cette classe et ce type dattribut pour stocker nimporte quel type de donnes.

332

10. Appareil photo

Classe NSData
Le tableau ci-aprs rsume les principales mthodes de la classe NSData.
Tableau 10.3 : Principales mthodes de la classe NSData Thme Cration dinstances Signature Objet

+ (id) dataWithBytes: Cre une instance NSData partir (const void *)bytes dun tableau doctets. length:(NSUInteger)length + (id) dataWithContents Cre une instance NSData partir OfFile:(NSString *)path du contenu dun chier. + (id) dataWithContents Cre une instance NSData partir OfURL:(NSURL *)aURL du contenu dune URL.

Accder aux donnes

(const void *) bytes (NSUInteger) length

Renvoie un pointeur sur le tableau doctets encapsul dans le NSData. Renvoie la longueur en octets du tableau encapsul dans le NSData. Cre un chier avec le contenu de linstance NSData. Si flag vaut YES, le chier est cr uniquement si son intgrit peut tre garantie. Cre une URL avec le contenu de linstance NSData. Si flag vaut YES, lURL est cre uniquement si son intgrit peut tre garantie.

Enregistrer les donnes

(BOOL) writeToFile: (NSString *)path atomically:(BOOL)flag

(BOOL) writeToURL: (NSURL *) aURL atomically:(BOOL) atomically

Ces mthodes permettent la conversion dune instance NSData de et vers :


j j j

un tableau doctets en mmoire ; le contenu dun chier ; un contenu adress par une URL.

Le framework Cocoa Touch contient galement plusieurs fonctions utilitaires qui permettent de convertir des donnes particulires en instance NSData. Notamment les images, ce que nous allons voir la section suivante.

Transformer limage en data


La fonction UIImagePNGRepresentation prend une instance UIImage en paramtre et retourne une instance NSData contenant limage au format PNG. La mthode +imageWithData: de la classe UIImage ralise lopration inverse.

10.3. Enregistrer ses photos

333

1 Modiez les mthodes viewWillAppear: et imagePickerController: didFinishPickingMediaWithInfo: de la classe LendObjectView Controller pour enregistrer la photo slectionne dans la structure Core Data et la rcuprer :
- (void)viewWillAppear:(BOOL)animated{ if ( [self.lendObject valueForKey: @"lendDate"] ) { self.objectNameField.text = [self.lendObject valueForKey: @"objectName"] ; self.borrowerNameField.text = [self.lendObject valueForKey: @"borrowerName"] ; self.datePicker.date = [self.lendObject valueForKey: @"lendDate"] self.imageView.image = [UIImage imageWithData:[self.lendObject valueForKey: @"image"]] ; } [super viewWillAppear:animated]; } - (void)imagePickerController:(UIImagePickerController *) picker didFinishPickingMediaWithInfo:(NSDictionary *)info{ UIImage *picture = [info objectForKey:UIImagePickerControllerOriginalImage]; [self.lendObject setValue: UIImagePNGRepresentation(picture) forKey: @"image"] ; [self dismissModalViewControllerAnimated:YES]; }

Dans cette classe, vous pouvez galement supprimer la proprit picture qui est dsormais inutile. 2 Reconstruisez et testez lapplication pour vrier que les images sont conserves avec les donnes des objets prts.

Le modle Core Data a t modifi


Pour tester cette nouvelle version de lapplication, il faudra dabord supprimer la version prcdente sur le simulateur ou sur lappareil. Par dfaut, Core Data ncessite que le chier de stockage utilis soit lu et produit avec le mme modle.

Challenge
Si vous disposez dun iPhone 3GS, vous pouvez modier lapplication pour conserver une capture vido plutt quune photo.

Enregistrer dans lalbum


Le framework Cocoa Touch propose des fonctions permettant denregistrer des images, photos ou des vidos dans les albums par dfaut de lappareil.
334
10. Appareil photo

Enregistrement dune image


Pour enregistrer une image ou une photo dans lalbum, utilisez la fonction qui prend pour paramtres :
j j

une rfrence limage enregistrer, de type UIImage * ; une rfrence lobjet, de type id, devant recevoir la notication de lenregistrement, ou nil si vous ne souhaitez pas que lapplication soit informe de la n de lenregistrement ; le slecteur de la mthode appeler pour la notication de lenregistrement, ou nil ; une rfrence de type void * sur des informations, qui sera passe la mthode de notication, ou nil sil ny a pas dinformations complmentaires transmettre.

Le slecteur de la mthode de notication doit prendre trois paramtres :


j

la rfrence limage qui vient dtre enregistre, de type


UIImage * ;

une rfrence vers une instance NSError contenant la description de lerreur ventuelle ; la rfrence vers les informations complmentaires.

Enregistrement dune vido


Pour enregistrer une capture vido dans lalbum, utilisez la fonction UISaveVideoAtPathToSavedPhotosAlbum qui prend pour paramtres : j une chane de caractres contenant le chemin daccs vers la vido, de type NSString * ; j une rfrence lobjet, de type id, devant recevoir la notication de lenregistrement, ou nil si vous ne souhaitez pas que lapplication soit informe de la n de lenregistrement ; j le slecteur de la mthode appeler pour la notication de lenregistrement, ou nil ; j une rfrence de type void * sur des informations, qui sera passe la mthode de notication, ou nil sil ny a pas dinformations complmentaires transmettre. Le slecteur de la mthode de notication doit prendre trois paramtres : j le chemin daccs la vido qui vient dtre enregistre, de type NSString * ;
j

une rfrence vers une instance NSError contenant la description de lerreur ventuelle ; la rfrence vers les informations complmentaires.
10.3. Enregistrer ses photos

335

10.4. diter les photos


Le slectionneur de photos est dot dun diteur lmentaire qui permet lutilisateur de recadrer et de zoomer limage avant de la slectionner. Pour utiliser cet diteur, il faut :
j

lactiver avant dafficher le slectionneur, ce qui est ralis avec la proprit boolenne allowsEditing ; choisir limage dite plutt que limage originale.

Pour utiliser lditeur de photos dans lapplication Emprunts3, modiez les mthodes takePicture et imagePickerController:didFinish PickingMediaWithInfo: :
- (void) takePicture { UIImagePickerController *picker = [[UIImagePickerController alloc] init]; if ([UIImagePickerController isSourceTypeAvailable: UIImagePickerControllerSourceTypeCamera]){ picker.sourceType = UIImagePickerControllerSourceTypeCamera; } else { picker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary; } picker.allowsEditing = YES; picker.delegate = self; [self presentModalViewController:picker animated:YES]; [picker release]; } - (void)imagePickerController: (UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info{ UIImage *picture = [info objectForKey:UIImagePickerControllerEditedImage]; [self.lendObject setValue: UIImagePNGRepresentation(picture) forKey: @"image"] ; [self dismissModalViewControllerAnimated:YES]; }

Vous pouvez reconstruire lapplication pour la tester.

10.5. Envoyer ses photos


Le framework MessageUI permet denvoyer des courriels depuis une application. La classe MFMailComposeViewController qui y est dnie est un contrleur de composition de courriel. Il prsente une interface standard lutilisateur, lui permettant de composer un message

336

10. Appareil photo

et de le transmettre. Les diffrents champs du courriel peuvent tre prremplis par lapplication : destinataire, objet, pices jointes, etc.

Classe MFMailComposeViewController
La classe MFMailComposeViewController sutilise comme la plupart des contrleurs de vue utilitaires, UIImagePickerController par exemple :
j j

cration dune instance du contrleur de vue ; initialisation des proprits de cette instance, en particulier son dlgu ; activation du contrleur par presentModalViewController:animated:.

Le dlgu du contrleur est inform lorsque lutilisateur souhaite fermer linterface de composition, soit pour envoyer le courriel, soit pour lenregistrer dans les brouillons, soit pour annuler. Les mthodes et proprits de la classe MFMailComposeViewController sont rpertories dans le tableau.
Tableau 10.4 : Mthodes et proprits de la classe MFMailComposeViewController Thme Capacit denvoyer des courriels Prremplissage des champs Signature Objet Retourne YES si lappareil est congur pour envoyer des courriels. Prremplit le champ Objet. Prremplit le champ Destinataires. Prremplit le champ Copies.

+ (BOOL)canSendMail

(void) setSubject: (NSString*)subject (void) setToRecipients: (NSArray*)toRecipients (void) setCcRecipients: (NSArray*)ccRecipients

(void) setBccRecipients: Prremplit le champ Copies (NSArray*)bccRecipients caches. (void) setMessageBody: (NSString*)body isHTML:(BOOL)isHTML
Prremplit le champ Texte.

(void) addAttachmentData: Attache un document en pr(NSData*)attachment cisant son contenu, son type mimeType:(NSString*)mimeType MIME et son nom. fileName:(NSString*)filename
Dlgu

@property(nonatomic,assign) Dlgu du contrleur de id<MFMailComposeView composition de courriel ControllerDelegate> mailComposeDelegate

10.5. Envoyer ses photos

337

types MIME
Le type MIME permet au destinataire du message dexploiter le chier attach en prcisant son format. Par exemple, un chier de texte pur est de type text/plain, une image au format PNG de type image/png, etc. La liste des types existants est disponible ladresse http://www.iana.org /assignments/media-types/.

Protocole MFMailComposeViewControllerDelegate
Le dlgu du contrleur de composition de courriel est inform lorsque lutilisateur souhaite fermer la vue de composition. Le protocole MFMailComposeViewControllerDelegate ne dclare quune mthode.
Tableau 10.5 : Mthodes du protocole MFMailComposeViewControllerDelegate Mthode Objet Mthode appele lorsque lutilisateur veut refermer la fentre de composition de courriel.

(void) mailComposeController: (MFMailComposeViewController*) controller didFinishWith Result:(MFMailComposeResult) result error:(NSError*)error

Cest dans cette mthode que le dveloppeur doit appeler dismissModalViewControllerAnimated: pour dsactiver le contrleur de composition de courriel. Les valeurs de retours MFMailComposeResult sont :
j

dnies

dans

le

type

numr

MFMailComposeResultCancelled si lutilisateur a annul la composition ; MFMailComposeResultSaved si lutilisateur a enregistr le courriel dans les brouillons ; MFMailComposeResultSent si lutilisateur a envoy le courriel ; MFMailComposeResultFailed en cas derreur.

j j

lenvoi est diffr


Un rsultat MFMailComposeResultSent ne signie pas que le courriel est effectivement parti. Il a t plac dans la bote denvoi et sera envoy la

338

10. Appareil photo

premire occasion, par exemple lorsque lappareil accrochera un rseau Wi-Fi.

Challenge
Compltez lapplication Emprunts3 en ajoutant la capacit denvoyer la photo prise lors du prt. Cela vous permettra de vous rappeler au bon souvenir des amis indlicats

10.6. Checklist
Nous avons appris dans ce chapitre utiliser lalbum photo de lappareil, et lappareil de prise de vues ou de capture vido pour ceux qui en sont dot. Pour cela, nous avons dtaill le fonctionnement :
j j

de la classe UIImagePickerController ; du protocole UIImagePickerControllerDelegate.

Nous avons vu comment utiliser la classe NSData pour enregistrer et rcuprer des images dans une structure Core Data, grce aux attributs de type binaire. Nous savons maintenant doter nos applications de la capacit de prparer et envoyer des courriels avec le framework MessageUI :
j j

classe MFMailComposeViewController ; protocole MFMailComposeViewControllerDelegate.

10.6. Checklist

339

GO-LOCALISATION

Dterminer sa position ........................................................................................... 343 Dterminer lorientation gographique .......................................................... 349 Framework MapKit ................................................................................................... 352 Checklist ........................................................................................................................ 360

341

CHAPITRE 11

Deux frameworks sont au programme de ce chapitre : j CoreLocation, qui permet dutiliser les capacits de golocalisation de liPhone ; j MapKit, qui permet dinsrer des cartes gographiques dans une application et qui sutilise en conjonction avec CoreLocation, par exemple, pour y visualiser des marqueurs.

11.1. Dterminer sa position


Technologies de go-localisation
LiPhone met en uvre simultanment plusieurs technologies pour localiser sa position gographique : j la localisation des rseaux Wi-Fi publics, qui est une technologie relativement prcise (quelques dizaines de mtres), mais nest pas disponible partout ; j la triangulation des antennes relais de tlphonie mobile, partout disponible mais avec une prcision trs variable (en montagne, par exemple, le nombre dantennes relais accessibles est souvent insuffisant pour obtenir une bonne prcision) ; j le positionnement par satellites GPS, trs prcis en plein air et gnralement indisponible lintrieur des btiments. La prcision de la go-localisation va de plusieurs kilomtres quelques mtres. Il faut tre conscient quune bonne prcision ncessite des calculs, donc du temps (souvent plusieurs secondes), et consomme galement de lnergie. Il est recommand de limiter la prcision demande au strict ncessaire en fonction de lapplication. La mise en uvre des diffrentes technologies de go-localisation est transparente pour le dveloppeur. Le gestionnaire de golocalisation en masque la complexit pour se concentrer sur lessentiel : fournir une localisation avec le niveau de prcision requis.

Classe CLLocationManager
Mise en uvre du gestionnaire de go-localisation
La mise en uvre de la go-localisation utilise un motif analogue celui du slectionneur dimages vu au chapitre prcdent et celui des acclromtres que nous verrons au chapitre suivant :
j

Cration dune instance de la classe CLLocationManager (le gestionnaire de go-localisation) qui est programme pour dnir les critres de notications relatifs la position gographique de lappareil.

11.1. Dterminer sa position

343

Activation du gestionnaire ; il commence dlivrer des notications. j Les notications sont dlivres au dlgu du gestionnaire qui doit rpondre au protocole CLLocationManagerDelegate. j Le gestionnaire est dsactiv lorsque les notications ne sont plus ncessaires. Les deux premires tapes sont ralises typiquement par les instructions suivantes :
j

locationManager = [[CLLocationManager alloc] init]; locationManager.delegate = self; locationManager.desiredAccuracy = kCLLocationAccuracyKilometer; locationManager.distanceFilter = 500.; [locationManager startUpdatingLocation];

Dans ce cas, le gestionnaire est programm pour dlivrer des notications prcise au kilomtre prs et chaque fois que lappareil sest dplac de 500 mtres ou plus. Les notications sont reues par le dlgu sur sa mthode locationManager:didUpdateToLocation:fromLocation: dtaille dans la section relative au protocole CLLocationManagerDelegate. La dernire tape est ralise par linstruction suivante :
[locationManager stopUpdatingLocation];

Dtails de la classe CLLocationManager


La classe CLLocationManager permet de grer les notications relatives la position gographique de lappareil et celles relatives son orientation par rapport au Nord, dont il sera question plus loin dans ce chapitre. Les mthodes et proprits de la classe sont dtailles dans le tableau ci-aprs.
Tableau 11.1 : Mthodes et proprits de la classe CLLocationManager Thme Conguration des mises jour de la position Signature Objet

@property(assign, Dlgu du gestionnaire de goNS_ NONATOMIC_ IPHONEONLY) localisation id<CLLocationManager Delegate> delegate @property(assign, Distance de dplacement miniNS_ NONATOMIC_IPHONEONLY) male entre deux vnements de CLLocation mise jour de la position Distance distanceFilter @property(assign, NS_NONATOMIC_IPHONEONLY) CLLocation Accuracy desiredAccuracy
Prcision demande (non garantie)

344

11. Go-localisation

Tableau 11.1 : Mthodes et proprits de la classe CLLocationManager Thme Conguration des mises jour des directions Signature Objet Distance de dplacement minimale entre deux vnements de mise jour de la direction du Nord Retourne YES si lappareil dispose de la capacit de dterminer la direction du Nord (compas magntique). Dmarre les mises jour de golocalisation. Stoppe les mises jour de golocalisation. Dmarre les mises jour de la direction du Nord. Stoppe les mises jour de la direction du Nord. Referme le panneau de calibration magntique.

@property(assign, nonatomic) CLLocation Degrees headingFilter @property(readonly, nonatomic) BOOL headingAvailable

Dmarrer et arrter les mises jour

(void) startUpdating Location (void) stopUpdating Location (void) startUpdating Heading (void) stopUpdating Heading (void) dismissHeading CalibrationDisplay

Disponibilit des services de golocalisation

YES si lutilisateur de lappareil a @property(readonly, NS_ NONATOMIC_IPHONEONLY) autoris la go-localisation dans BOOL locationServices les prfrences systme Enabled @property(copy, nonatomic) NSString *purpose
Chane de caractres afficher en mme temps que le message demandant lutilisateur lautorisation dutiliser la go-localisation

Dernire position mise jour Obtenir la position @property(readonly, NS_ NONATOMIC_IPHONEONLY) de lappareil

CLLocation *location

La plupart des proprits de la classe CLLocationManager sont dclares avec une clause NS_NONATOMIC_IPHONEONLY. En effet, le framework CoreLocation tant commun Cocoa sur Mac OS X et Cocoa Touch sur iPhone OS, cette dclaration permet de dnir des proprits atomiques sur Mac OS X et non-atomiques sur iPhone OS. Rappelons quune proprit est dite atomique si ses accesseurs permettent den garantir la validit, mme dans un environnement multithreading o le mme objet peut tre manipul simultanment par plusieurs threads. La priorit est mise sur lintgrit des donnes sur Mac OS X (on peut utiliser le mme gestionnaire simultanment dans plusieurs threads), alors quelle est mise sur les performances sur iPhone OS.

11.1. Dterminer sa position

345

Proprit purpose
La proprit purpose est disponible uniquement partir de la version 3.2.

Types scalaires
Outre la classe CLLocationManager, le framework Core Location dnit galement la classe CLLocation et le protocole CLLocation ManagerDelegate, que nous dtaillerons plus loin, ainsi que les types scalaires dcrits ci-aprs.
Tableau 11.2 : Types scalaires CLLocation Type CLLocation Type C Utilisation Prcision de distance en mtres Le champ latitude prend une valeur comprise entre -90 et +90 (une valeur positive indique une latitude dans lhmisphre Nord et ngative dans lhmisphre Sud) Le champ longitude prend une valeur comprise entre -180 et +180 (une valeur positive indique une longitude lEst du mridien de Greenwich, et ngative lOuest) Angle en degrs Direction du Nord en degrs Distance en mtres Vitesse en mtres par seconde

CLLocation Accuracy CLLocation Coordinate2D

double struct { CLLocation Degrees latitude; CLLocation Degrees longitude;} double double double double

CLLocation Degrees CLLocation Direction CLLocation Distance CLLocation Speed

Quelques constantes sont dnies dans le framework Core Location pour en faciliter lusage :
j

kCLDistanceFilterNone, de type CLLocationDistance, est utilis avec la proprit distanceFilter du gestionnaire de go-localisation pour lui indiquer de ne pas ltrer les notications de position.

Plusieurs constantes sont dnies pour le type CLLocationAccuracy et la proprit desiredAccuracy du gestionnaire de golocalisation :
kCLLocationAccuracyBest pour obtenir la meilleure prcision possible ;

346

11. Go-localisation

kCLLocationAccuracyNearestTenMeters pour obtenir une position 10 mtres prs ; kCLLocationAccuracyHundredMeters pour obtenir une position 100 mtres prs ; kCLLocationAccuracyKilometer pour obtenir une position 1 kilomtre prs ; kCLLocationAccuracyThreeKilometers pour obtenir une position 3 kilomtres prs.

Protocole CLLocationManagerDelegate
Le tableau rsume les mthodes dclares dans le protocole CLLocationManagerDelegate. Toutes ces mthodes sont optionnelles.
Tableau 11.3 : Mthodes du protocole CLLocationManagerDelegate Thme vnements de mise jour de la golocalisation Signature Objet Mise jour de la golocalisation. La mthode reoit la nouvelle position et lancienne.

vnements de mise jour de la direction du Nord

(void) locationManager: (CLLocationManager *) manager didUpdateTo Location:(CLLocation *)newLocation from Location:(CLLocation *)oldLocation (void) locationManager: (CLLocationManager *) manager didFailWith Error:(NSError *)error (void) locationManager: (CLLocationManager *) manager didUpdate Heading:(CLHeading *) newHeading (BOOL) locationManager ShouldDisplayHeading Calibration: (CLLocationManager *) manager

Une erreur sest produite pendant la go-localisation.

Mise jour de la direction du Nord. La mthode reoit la nouvelle direction.

Doit retourner YES si le dlgu autorise laffichage du panneau de calibration magntique.

Le dlgu du gestionnaire de go-localisation reoit les notications :


j

des mises jour de la go-localisation de lappareil, pour savoir o se situe lappareil sur le globe terrestre ; des mises jour de la direction du Nord, pour savoir commet est orient lappareil par rapport au Nord.

Le protocole CLLocationManagerDelegate permet galement au dlgu dtre inform dune erreur de go-localisation ou de la nces11.1. Dterminer sa position

347

sit dune calibration magntique (voir plus loin la section Dterminer lorientation gographique).

Classe CLLocation
Les notications de go-localisation dlivrent la position de lappareil sous forme dinstances de la classe CLLocation dcrite dans le tableau ci-aprs.
Tableau 11.4 : Mthodes et proprits de la classe CLLocation Thme Initialisation Signature Objet Cre une instance avec les coordonnes passes en paramtre. La prcision horizontale prend une valeur nulle, la prcision verticale prend la valeur 1. Lhorodate est celle de linitialisation de lobjet. Cre une instance avec les donnes passes en paramtre.

(id) initWithLatitude: (CLLocationDegrees) latitude longitude: (CLLocationDegrees) longitude (id) initWith Coordinate:(CLLocation Coordinate2D)coordinate altitude:(CLLocation Distance)altitude horizontalAccuracy: (CLLocationAccuracy) hAccuracyvertical Accuracy:(CLLocation Accuracy)vAccuracy timestamp:(NSDate *) timestamp @property(readonly, NS_NONATOMIC_IPHONEONLY) CLLocationCoordinate2D coordinate @property(readonly, NS_NONATOMIC_IPHONEONLY) CLLocationDistance altitude @property(readonly, NS_NONATOMIC_IPHONEONLY) CLLocationAccuracy horizontalAccuracy @property(readonly, NS_NONATOMIC_IPHONEONLY) CLLocationAccuracy verticalAccuracy @property(readonly, NS_NONATOMIC_IPHONEONLY) NSDate *timestamp (NSString *)description

Attributs de golocalisation

Coordonnes de la position

Altitude

Prcision horizontale

Prcision verticale

Horodate laquelle la position a t dtermine Retourne une chane de caractres contenant la description de la position.

348

11. Go-localisation

Tableau 11.4 : Mthodes et proprits de la classe CLLocation Thme Mesure de distance Signature Objet Retourne la distance entre la position du rcepteur et celle de linstance passe en paramtre. Vitesse instantane de lappareil. Une valeur ngative indique que cette proprit est indisponible. Direction de dplacement de lappareil Une valeur ngative indique que cette proprit est indisponible.

(CLLocationDistance) getDistanceFrom:(const CLLocation *)location Dtermina- @property(readonly, tion du mou- NS_NONATOMIC_IPHONEONLY) CLLocationSpeed speed vement @property(readonly, NS_NONATOMIC_IPHONEONLY) CLLocationDirection course

La classe CLLocation permet non seulement de retrouver la position de lappareil, sous forme de latitude et de longitude, mais aussi :
j j j j

laltitude de lappareil ; la prcision horizontale et verticale ; lhorodate prcise de la mesure ; sil y a lieu, la vitesse et la direction de dplacement de lappareil.

Challenge
Ralisez une application qui affiche la position de lappareil. Vous pourrez agrmenter cette application de fonctions permettant lutilisateur de jouer sur la prcision recherche et sur le ltre en distance pour les notications de go-localisation.

11.2. Dterminer lorientation gographique


LiPhone 3GS est dot dun compas magntique permettant soit de mesurer un champ magntique, soit de dterminer linclinaison de lappareil par rapport la direction du Nord ; les applications Boussole et Plans (sur iPhone 3GS) utilisent le compas magntique. Le compas magntique est mis en uvre dans une application laide du gestionnaire de go-localisation dont nous venons de traiter. Il peut tre tonnant au premier abord de mlanger la go-localisation et la dtection magntique dans un mme framework. Lexplication est simple, la dtermination de la direction du Nord gographique ncessite la connaissance de la position de lappareil sur le globe terrestre an de calculer la dclinaison magntique ; lcart entre les directions du Nord gographique et du Nord magntique.

11.2. Dterminer lorientation gographique

349

Mise en uvre du compas magntique


La mise en uvre du compas magntique utilise le gestionnaire de golocalisation et son motif standard. Les mthodes et proprits traitant de la go-localisation et du compas magntique y sont bien spares :
j

Une instance de la classe CLLocationManager (le gestionnaire de go-localisation) est cre. On vrie que le compas magntique est disponible sur lappareil avec la proprit headingAvailable. Le gestionnaire de go-localisation est programm pour dnir les critres de notication relatifs la linclinaison de lappareil par rapport la direction du Nord. Le gestionnaire est activ ; il commence dlivrer des notications. Les notications sont dlivres au dlgu du gestionnaire qui doit rpondre au protocole CLLocationManagerDelegate. Le gestionnaire est dsactiv lorsque les notications ne sont plus ncessaires.

j j

Les quatre premires tapes sont ralises typiquement par les instructions suivantes :
locationManager = [[CLLocationManager alloc] init]; if (locationManager.headingAvailable) then { locationManager.delegate = self; locationManager.headingFilter = 5.; [locationManager startUpdatingHeading]; }

Dans ce cas, le gestionnaire est programm pour dlivrer des notications chaque fois que linclinaison de lappareil change de 5 degrs ou plus. Les notications sont reues par le dlgu sur sa mthode locationManager:didUpdateHeading: dtaille dans la section relative au protocole CLLocationManagerDelegate. La dernire tape est ralise par linstruction suivante :
[locationManager stopUpdatingHeading];

un seul dlgu
Bien que les mthodes et proprits relatives la go-localisation et au compas magntique soient spares dans la classe CLLocationManager et dans le protocole associ, le dlgu du gestionnaire de go-localisation est unique pour ces deux fonctionnalits.

350

11. Go-localisation

Calibration magntique
Un compas magntique tant trs sensible aux perturbations, frquentes dans notre univers domestique et ses nombreux appareils lectroniques, le gestionnaire de go-localisation peut avoir afficher un panneau de calibration. Ce dernier invite lutilisateur faire des 8 avec lappareil ou sloigner dune source magntique trop forte. Dans ce cas, le dlgu du gestionnaire reoit le message locationManagerShouldDisplayHeadingCalibration:. Il doit rpondre YES sil autorise laffichage du panneau et NO dans le cas contraire. Par dfaut, sil nimplmente pas cette mthode, le panneau nest pas affich.

Classe CLHeading
Linformation dinclinaison par rapport au Nord est transmise au dlgu sous la forme dune instance de la classe CLHeading.
Tableau 11.5 : Mthodes et proprits de la classe CLHeading Thme Signature Objet Direction vers laquelle pointe le sommet de lappareil, par rapport au Nord magntique (0 pour le Nord, 90 pour lEst, etc.) Une valeur ngative indique que cette proprit ne peut tre calcule. Direction vers laquelle pointe le sommet de lappareil, par rapport au Nord gographique (0 pour le Nord, 90 pour lEst, etc.) Une valeur ngative indique que cette proprit ne peut tre calcule. Le calcul de cette proprit ncessite que lappareil puisse tre go-localis. Estimation de lerreur sur la direction du Nord magntique Une valeur ngative indique que cette proprit ne peut tre calcule. Horodate de la mesure du compas magntique Description de la mesure du compas magntique sous forme de chane de caractres Attributs de Direction @property(readonly,

nonatomic) CLLocation Direction magneticHeading

@property(readonly, nonatomic) CLLocation Direction trueHeading

@property(readonly, nonatomic) CLLocation Direction headingAccuracy @property(readonly, nonatomic) NSDate *timestamp (NSString *) description

11.2. Dterminer lorientation gographique

351

Tableau 11.5 : Mthodes et proprits de la classe CLHeading Thme Mesures brutes Signature Objet Mesure du champ magntique en microTesla selon laxe des abscisses Mesure du champ magntique en microTesla selon laxe des ordonnes Mesure du champ magntique en microTesla selon laxe des profondeurs

@property(readonly, nonatomic) CLHeading ComponentValue x @property(readonly, nonatomic) CLHeading ComponentValue y @property(readonly, nonatomic) CLHeading ComponentValue z

La proprit magneticHeading contient linclinaison de laxe de lappareil par rapport la direction du Nord magntique. La proprit trueHeading contient linclinaison par rapport au Nord gographique.

le Nord gographique ncessite la go-localisation


La proprit trueHeading est mise jour uniquement si la notication de la go-localisation est active sur le gestionnaire de go-localisation.

11.3. Framework MapKit


Lorsque lon traite de go-localisation, le besoin de visualiser une carte vient naturellement. Nous allons voir dans cette section comment afficher une carte et permettre lutilisateur dinteragir avec elle ; nous mettrons en uvre le framework MapKit.

Afficher une carte


Crez un nouveau projet sous XCode, de type View Based Application. Nommez-le Carte.

Ajouter le framework MapKit


Le framework MapKit nest pas intgr par dfaut aux projets XCode ; rappelons la dmarche suivre pour ajouter un framework un projet : 1 Dans la zone Groups&Files de la fentre principale, ouvrez le groupe Targets, slectionnez la cible Carte et cliquez du bouton droit pour afficher le menu contextuel.

352

11. Go-localisation

2 Slectionnez la commande Get Info. Dans le panneau dinformation qui saffiche, choisissez longlet General et cliquez sur le bouton + de la partie Linked Libraries. 3 Choisissez le chier MapKit.framework pour ajouter le framework MapKit au projet Carte.

Ajouter une vue Carte


1 Sous XCode, double-cliquez sur le chier CarteViewController.xib pour louvrir. Ajoutez une vue cartographique (Map View) sur linterface utilisateur (voir Figure 11.1). 2 Utilisez linspecteur de taille (X+[3]) pour dnir une vue carre, par exemple une hauteur et une largeur de 280 pixels. La vue cartographique que nous venons dinsrer est de la classe MKMapView. Dans la suite de ce chapitre, nous examinerons les caractristiques les plus courantes de la classe MKMapView qui est au centre du framework MapKit.

Figure 11.1 : Vue cartographique sous Interface Builder

11.3. Framework MapKit

353

Tester lapplication
Construisez lapplication sous XCode et testez-la (X+[R]).

Figure 11.2 : Carte affiche par dfaut

Par dfaut, la carte affiche est celle du pays dni dans les prfrences de localisation de lappareil ou le planisphre complet. Vous pouvez la dplacer ou zoomer. Nous allons voir comment connatre et contrler le positionnement de la carte par programmation.

Connatre la zone affiche


La zone affiche sur la carte est accessible par la proprit region de la classe MKMapView. Nous allons en illustrer le fonctionnement en modiant lapplication Carte pour que lutilisateur puisse en visualiser les caractristiques.

Dnir les outlets


Sous Interface Builder, ajoutez quatre labels de texte sur la vue principale an dy afficher les coordonnes du centre de la carte (latitude et longitude) et la taille de la zone affiche (hauteur et largeur). 1 Sous XCode, ouvrez le chier CarteViewController.h pour y ajouter les outlets permettant daccder aux lments de la vue principale.

354

11. Go-localisation

Nous y dnissons galement le contrleur comme rpondant au protocole MKMapViewDelegate pour quil soit noti des changements sur la carte :
#import <UIKit/UIKit.h> #import <MapKit/MapKit.h> @interface CarteViewController : UIViewController <MKMapViewDelegate> { IBOutlet MKMapView * carte; IBOutlet UILabel * latitudeLabel; IBOutlet UILabel * longitudeLabel; IBOutlet UILabel * hauteurLabel; IBOutlet UILabel * largeurLabel; } @property(retain,nonatomic) MKMapView * carte; @property(retain,nonatomic) UILabel * latitudeLabel; @property(retain,nonatomic) UILabel * longitudeLabel; @property(retain,nonatomic) UILabel * hauteurLabel; @property(retain,nonatomic) UILabel * largeurLabel; @end

inclure MapKit.h
Le framework MapKit ntant pas inclus par dfaut dans le projet, il faut ajouter une clause #import <MapKit/MapKit.h> dans les chiers sources qui doivent lutiliser.

2 Revenez sous Interface Builder pour attacher les outlets du contrleur aux lments de la vue et dnissez le dlgu de la vue MKMapView comme tant le propritaire du chier.

Figure 11.3 : Liens de la vue MKMapView

Code source du contrleur de vue


1 Sous XCode, ajoutez les accesseurs des proprits de la classe CarteViewController dans son chier source :
@implementation CarteViewController @synthesize carte, latitudeLabel, longitudeLabel, hauteurLabel, largeurLabel;

11.3. Framework MapKit

355

2 Ajoutez la dnition de la mthode mapView:regionDidChange Animated: du protocole MKMapViewDelegate. Cette mthode est appele chaque fois que la proprit region est modie :
- (void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated{ MKCoordinateRegion region = carte.region; latitudeLabel.text = [NSString stringWithFormat:@"%g", region.center.latitude]; longitudeLabel.text = [NSString stringWithFormat:@"%g", region.center.longitude]; hauteurLabel.text = [NSString stringWithFormat:@"%g", region.span.latitudeDelta]; largeurLabel.text = [NSString stringWithFormat:@"%g", region.span.longitudeDelta]; }

3 Construisez lapplication pour la tester.

Figure 11.4 : Visualisation des caractristiques de la rgion affiche

Proprit region
La proprit region de la classe MKMapView est une structure de type MKCoordinateRegion compose de :
j

center qui est une structure de type CLLocationCoordinate2D ellemme compose de : latitude de type CLLocationDegrees ; longitude de type CLLocationDegrees.

356

11. Go-localisation

span qui est une structure de type MKCoordinateSpan compose de : latitudeDelta de type CLLocationDegrees ; longitudeDelta de type CLLocationDegrees.

Ainsi une rgion sur la carte est dnie par son centre (latitude et longitude) et par sa taille, elle-mme exprime en carts de latitude et de longitude. Un cart de latitude de un degr reprsente une hauteur de 111 km. Un cart de longitude de un degr reprsente une largeur qui dpend de la latitude : 111 km lquateur et 0 aux ples.

Contrler la zone affiche


Maintenant que nous savons extraire la zone affiche dans une instance de la classe MKMapView, nous allons complter notre application Carte an quelle nous permette de mmoriser une rgion pour y revenir plus tard.

Dnir linterface
1 Ajoutez deux boutons sur linterface utilisateur, Dnir Zone et Retrouver Zone. Ajoutez une action pour chacun de ces boutons dans linterface du contrleur de vue de lapplication, respectivement defineZone et retrieveZone. Liez les boutons et les actions sous Interface Builder. 2 Toujours dans linterface du contrleur de vue, dclarez une nouvelle proprit zone de type MKCoordinateRegion. Cette proprit ntant pas une rfrence, elle doit tre dclare avec la clause assign au lieu de retain.

Code du contrleur
1 Dans le chier CarteViewController.m, synthtisez les accesseurs de la nouvelle proprit zone, puis dnissez les mthodes pour les actions :
-(IBAction) defineZone{ self.zone = carte.region; } -(IBAction) retrieveZone{ [carte setRegion:self.zone animated:YES]; }

Nous utilisons ici la mthode setRegion:animated: de la classe MKMapView pour dnir la rgion visualiser sur la carte. 2 Construisez lapplication pour la tester.
11.3. Framework MapKit

357

Apprhender la vue satellite


La classe MKMapView dispose des proprits suivantes pour modier son comportement :
j j j

mapType de type MKMapType ; scrollEnabled de type Boolen ; zoomEnabled de type Boolen.

scrollEnabled et zoomEnabled permettent dautoriser respectivement le dplacement de la carte et le zoom par lutilisateur. Ces proprits ont la valeur YES par dfaut. MKMapType est un type numr qui permet de dnir le type de visualisation de la carte :
j j j

MKMapTypeStandard, pour visualiser le plan ; MKMapTypeSatellite, pour visualiser la vue satellite ; MKMapTypeHybrid, pour visualiser la vue satellite augmente dinformation.

Challenge
Modiez lapplication Carte pour que lutilisateur puisse choisir entre les diffrents types de visualisation.

Figure 11.5 : Diffrents types de visualisation

358

11. Go-localisation

Annoter la carte
Nous allons terminer ce parcours du framework MapKit par la mise en uvre du protocole MKAnnotation et de la mthode addAnnotation: qui permettent dajouter sur la carte des marqueurs en forme dpingle tte.

Crer une annotation


Il ny a pas de classe spcique pour contenir une annotation. Nimporte quel objet fait laffaire pourvu quil respecte le protocole MKAnnotation qui dnit trois proprits :
j

coordinate, proprit obligatoire de type CLLocationCoordinate2D, pour dnir lemplacement du marqueur sur la carte ; title et subTitle, proprits optionnelles de type NSString * ; ces chanes de caractres sont affiches lorsque lutilisateur touche le marqueur.

Procdez ainsi : 1 Sous XCode, crez une nouvelle classe Annotation drivant de NSOject. Compltez linterface de la classe pour y dclarer quelle adopte le protocole MKAnnotation et ses proprits :
#import <Foundation/Foundation.h> #import <MapKit/MapKit.h> @interface Annotation : NSObject <MKAnnotation> { CLLocationCoordinate2D coordinate; NSString * title; NSString * subTitle; } @property(assign,nonatomic) CLLocationCoordinate2D coordinate; @property(retain,nonatomic) NSString * title; @property(retain,nonatomic) NSString * subTitle; @end

2 Compltez la dnition de la classe en dnissant les accesseurs pour les proprits dans le chier Annotation.m. Cette classe est un rceptacle de donnes, elle ne contient pas dautres mthodes :
#import "Annotation.h" @implementation Annotation @synthesize coordinate, title, subTitle; @end

Afficher un marqueur
1 Sous XCode, ouvrez le chier CarteViewController.m pour y dclarer la classe Annotation :
359

11.3. Framework MapKit

#import "Annotation.h"

2 Modiez la mthode defineZone pour ajouter un marqueur au centre de la carte :


-(IBAction) defineZone{ self.zone = carte.region; Annotation * annotation = [[Annotation alloc] init]; annotation.coordinate = self.zone.center; annotation.title = @"Centre de la zone"; [carte addAnnotation:annotation]; [annotation release]; }

3 Construisez lapplication pour la tester. Si vous touchez le marqueur dni en mme temps que la zone, le texte saffiche.

Figure 11.6 : Carte avec un marqueur

Nous vous laissons explorer le framework MapKit et les fonctions permettant dadapter les vues associes aux annotations.

11.4. Checklist
Nous connaissons maintenant les diffrentes technologies mises en uvre pour la go-localisation de lappareil, et nous savons mettre en uvre le framework Core Location : le gestionnaire de go-

360

11. Go-localisation

localisation, instance de la classe CLLocationManager, et son protocole de dlgu CLLocationManagerDelegate. Nous avons dtaill les classes dcrivant la position de lappareil :
j j

CLLocation pour la position sur le globe terrestre ; CLHeading pour linclinaison de lappareil par rapport au Nord, gographique ou magntique.

Enn, nous avons appris utiliser le framework MapKit, la vue MKMapView et son dlgu MKMapViewDelegate pour :
j j j j

visualiser et manipuler une carte ; connatre la zone gographique visualise ; modier le mode de visualisation de la carte ; insrer des annotations sur la carte.

11.4. Checklist

361

ACCLROMTRES

Utiliser les acclromtres .................................................................................... 365 Dterminer les mouvements de lappareil .................................................... 375 Connatre lorientation de lappareil ................................................................. 375 Checklist ........................................................................................................................ 381

363

CHAPITRE 12

Tous les appareils, iPhone et iPod Touch, sont dots de trois acclromtres. Grce ces derniers, on peut connatre lorientation de lappareil par rapport la verticale ainsi que ses mouvements ; ce chapitre est consacr ltude de leur utilisation. Nous commencerons par quelques exprimentations avec les classes UIAccelerometer et UIAcceleration, puis nous nous intresserons la dtection des mouvements et la dtermination de la position de lappareil.

Testez sur un appareil


Les exemples dvelopps dans ce chapitre ne fonctionnent pas sur le simulateur qui ne dispose pas dacclromtres.

Lannexe dcrit le mode opratoire suivre pour tester vos applications sur un appareil rel.

12.1. Utiliser les acclromtres


Nous allons commencer par crire une application nous permettant de visualiser les donnes fournies par les acclromtres. Elle sera notre support dexprimentation qui nous permettra de mieux comprendre le fonctionnement de ces "petites btes", et donc de mieux les utiliser par la suite.

Figure 12.1 : Visualiser les acclrations 365

12.1. Utiliser les acclromtres

Visualiser lacclration
1 Crez un projet de type View Based Application sous XCode et intitulez-le Accelero. Notre premire exprimentation contient trois labels, qui contiendront les composantes donnes par les trois acclromtres. Nous devons dnir les outlets pour ces labels dans notre contrleur de vue et il faut galement quil se conforme au protocole UIAccelerometerDelegate. 2 Modiez le chier AcceleroViewController.h :
#import <UIKit/UIKit.h> @interface AcceleroViewController : UIViewController <UIAccelerometerDelegate> { IBOutlet UILabel * xLabel; IBOutlet UILabel * yLabel; IBOutlet UILabel * zLabel; } @property(nonatomic,retain) UILabel * xLabel; @property(nonatomic,retain) UILabel * yLabel; @property(nonatomic,retain) UILabel * zLabel; @end

Le protocole UIAcceleromerDelegate dnit une seule mthode, (void)accelerometer:(UIAccelerometer *)didAccelerate: (UIAcceleration *) qui fournit :
j

une instance de UIAcceleromer reprsentant les trois acclromtres ; une instance de UIAcceleration, conteneur dune mesure dacclrations.

Tableau 12.1 : Proprits de la classe UIAcceleration Proprits Objet

@property(nonatomic, readonly) Acclration en g sur laxe des abscisses UIAccelerationValue x @property(nonatomic, readonly) Acclration en g sur laxe des ordonnes UIAccelerationValue y @property(nonatomic, readonly) Acclration en g sur laxe des profondeurs UIAccelerationValue z @property(nonatomic, readonly) Lhorodate de la mesure dacclration, en seNSTimeInterval timestamp condes, depuis le dmarrage de lappareil

366

12. Acclromtres

Type UIAccelerationValue
Le type UIAccelerationValue est quivalent au type double.

Orientation des axes


Les axes utiliss par les acclromtres sont les mmes que ceux dOpenGL ES ; lorsque lappareil est en mode Portrait, le bouton principal vers le bas, les abscisses sont disposes de gauche droite, les ordonnes du bas vers le haut et les profondeurs du dos vers lavant de lappareil

Figure 12.2 : Orientation des composantes dacclration

12.1. Utiliser les acclromtres

367

3 crivez le code de cette mthode de dlgu dans le chier AcceleroViewController.m. Nous voulons simplement afficher les valeurs des composantes de lacclration mesure :
- (void)accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acc { xLabel.text = [NSString stringWithFormat:@"%f", acc.x]; yLabel.text = [NSString stringWithFormat:@"%f", acc.y]; zLabel.text = [NSString stringWithFormat:@"%f", acc.z]; }

4 Activez les mesures et modiez la mthode viewDidLoad dans le chier AcceleroViewController.m :


- (void)viewDidLoad { [super viewDidLoad]; UIAccelerometer *accelerometer = [UIAccelerometer sharedAccelerometer]; accelerometer.updateInterval = 0.1; accelerometer.delegate = self; }

La variable accelerometer y est dnie comme linstance partage (unique) de la classe UIAccelerometer, puis nous dnissons la priodicit des mesures (1/10e de seconde, nous narriverons pas lire plus vite). Enn, nous dnissons le dlgu qui recevra les mesures. 5 Synthtisez les accesseurs des proprits avec @synthesize xLabel, yLabel, zLabel; et librez-les dans la mthode viewDidUnload :
- (void)viewDidUnload { self.xLabel = nil; self.yLabel = nil; self.zLabel = nil; }

6 Ouvrez le chier AcceleroViewController.xib pour placer trois labels dans la vue principale et les lier aux outlets du contrleur de vue. 7 Testez lapplication sur votre appareil rel ; le simulateur ne permet pas dmuler les acclromtres. Au besoin, consultez lannexe A qui dtaille le mode opratoire suivre pour charger et tester une application sur un appareil rel. Des valeurs non nulles saffichent, mme lorsque lappareil est immobile. Cest satisfaisant de voir que notre application affiche des lments mais il faut expliquer pourquoi notre appareil acclre quand il ne bouge pas.

368

12. Acclromtres

Un acclromtre est en fait un capteur de force, et tous les objets sur la Terre sont soumis la force de la gravitation. Nous voil dans la mme position quIsaac Newton qui eut lintuition de la loi de la gravitation universelle en observant la chute dune pomme ; nous dcouvrons la mme chose avec un iPhone, de marque Apple, videmment. Lorsque lappareil est au repos, nous mesurons lattraction terrestre.

Visualiser la verticale
Amliorons notre application Accelero pour visualiser la verticale par un segment de droite reprsentant la projection de la force dattraction sur lcran. Nous aurons besoin de dnir une vue spcique VerticalView dont la largeur sera de prfrence le double de la hauteur.

Figure 12.3 : Vue VerticalView

Modier le contrleur de vue


1 Modiez le chier AcceleroViewController.h pour y dnir un nouvel outlet de type VerticalView :
#import <UIKit/UIKit.h> @class VerticalView; @interface AcceleroViewController : UIViewController <UIAccelerometerDelegate> { IBOutlet UILabel * xLabel; IBOutlet UILabel * yLabel; IBOutlet UILabel * zLabel; IBOutlet VerticalView * vert; } @property(nonatomic,retain) UILabel * xLabel; @property(nonatomic,retain) UILabel * yLabel; @property(nonatomic,retain) UILabel * zLabel; @property(nonatomic,retain) VerticalView * vert; @end

Nous doterons notre vue VerticalView dune proprit vertLine de type GCSize qui contiendra les abscisses et ordonnes de lacclration.

12.1. Utiliser les acclromtres

369

2 Modiez le chier AcceleroViewController.m pour utiliser cette proprit :


- (void)accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acc { xLabel.text = [NSString stringWithFormat:@"%f", acc.x]; yLabel.text = [NSString stringWithFormat:@"%f", acc.y]; zLabel.text = [NSString stringWithFormat:@"%f", acc.z]; vert.vertLine = CGSizeMake(acc.x,acc.y); }

3 Dans ce mme chier, importez le chier VerticalView.h, synthtisez les accesseurs de la proprit vert et librez cette proprit.
Le type GCSize et la fonction GCSizeMake sont dtaills au chapitre Dessins et animations.

Crer la vue VerticalView


Cette classe met en uvre les techniques vues au chapitre Dessins et
animations. Elle doit assurer que :
j

Lorigine du segment se situe au milieu du bord suprieur de la vue. Nous avons besoin dune variable dinstance origin de type CGPoint pour conserver ce point. La longueur maximale du segment est la hauteur, ou la demilargeur, de la vue. Nous dnirons une variable dinstance scale de type CGFloat pour conserver cette longueur maximale. Le segment est toujours visible, quelle que soit lorientation de lappareil. Une variable dinstance endPoint de type CGPoint sera value chaque modication de la proprit vertLine.

Procdez ainsi : 1 Sous XCode, crez une nouvelle classe VerticalView drive de UIView. Dclarez son interface :
#import <UIKit/UIKit.h> @interface VerticalView : UIView { CGFloat scale; CGPoint origin; CGSize vertLine; CGPoint endPoint; } @property(nonatomic,assign) CGSize vertLine; @end

370

12. Acclromtres

Les variables dinstance scale et origin doivent tre values lorsque la vue est insre dans la hirarchie des vues et que sa taille est dnie. 2 Ajoutez la mthode layoutSubviews dans le chier VerticalView.m :
- (void) layoutSubviews { CGFloat height = self.bounds.size.height; CGFloat width = self.bounds.size.width; if (height<2.*width) scale = height; else scale = width/2.; origin = CGPointMake(width/2.,0.); }

Lorsque la proprit vertLine est modie, la variable dinstance endPoint doit tre value et la vue redessine. 3 Dnissez la mthode setVertLine: dans le chier VerticalView.m :
- (void)setVertLine:(CGSize)line{ vertLine = line; if (line.height<0) { endPoint.x = line.width*scale+origin.x; endPoint.y = -line.height*scale+origin.y; } else { endPoint.x = -line.width*scale+origin.x; endPoint.y = line.height*scale+origin.y; } [self setNeedsDisplay]; }

4 crivez la mthode drawRect: qui ne prsente pas de difficult particulire :


- (void)drawRect:(CGRect)rect { CGContextRef context = UIGraphicsGetCurrentContext(); CGContextSetRGBStrokeColor(context, 1., 0.5, 0., 1.0); CGContextSetLineWidth(context, 15.); CGContextSetLineCap(context, kCGLineCapRound); CGPoint segment[2] = {origin,endPoint}; CGContextStrokeLineSegments(context, segment, 2); }

Finaliser et tester lapplication


Noubliez pas de synthtiser les accesseurs de la proprit vertLine. 1 Ouvrez le chier AcceleroViewController.xib pour ajouter une vue sur linterface utilisateur. Dnissez sa classe : VerticalView. Liez cette vue loutlet vert du propritaire du chier. 2 Construisez lapplication pour la tester sur un appareil rel. Nous visualisons maintenant la verticale.

12.1. Utiliser les acclromtres

371

Figure 12.4 : Visualisation de la verticale

Mme lappareil au repos, la verticale gigote sans arrt. Les acclromtres sont sensibles et peroivent les vibrations de quelques milli-g. Si lon souhaite une verticale plus stable, ou connatre la position de lappareil en faisant abstraction des vibrations, il faut ltrer les donnes mesures.

Filtrer les donnes


Nous allons ajouter un ltre paramtrable notre application pour exprimenter un ltre numrique et en illustrer les effets.

Figure 12.5 : Application avec un ltre numrique

372

12. Acclromtres

1 Ouvrez le chier AcceleroViewController.m et modiez la mthode accelerometer:didAccelerate: :


- (void)accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acc { static UIAccelerationValue accelX=0.,accelY=0.,accelZ=0.; accelX = self.coef*acc.x + (1.-self.coef)*accelX; accelY = self.coef*acc.y + (1.-self.coef)*accelY; accelZ = self.coef*acc.z + (1.-self.coef)*accelZ; xLabel.text = [NSString stringWithFormat:@"%f",accelX]; yLabel.text = [NSString stringWithFormat:@"%f",accelY]; zLabel.text = [NSString stringWithFormat:@"%f",accelZ]; vert.vertLine = CGSizeMake(accelX,accelY); }

La mthode utilise une proprit coef et trois variables statiques qui contiennent le rsultat du calcul des composantes de lacclration. Si par exemple la proprit coef vaut 10 %, le rsultat du calcul est la somme de 10 % de la nouvelle mesure et 90 % du calcul prcdent. Ainsi les tremblements seront attnus. Nous utiliserons un ascenseur pour modier la valeur du coefficient, ceci facilitera lexprimentation du ltre et nous aidera comprendre son effet. 2 Ajoutez une mthode changeCoef: dans le chier AcceleroViewController.m. Elle sera laction dclenche par lvnement Change Value de lascenseur.
- (void)changeCoef:(id)sender{ self.coef = [[sender valueForKey:@"value"] floatValue]; self.coefLabel.text = [NSString stringWithFormat:@"%f",self.coef]; }

3 Synthtisez les accesseurs pour les nouvelles proprits et initialisez-les dans la mthode viewDidLoad :
@synthesize xLabel, yLabel, zLabel, coef, coefLabel, vert; - (void)viewDidLoad { [super viewDidLoad]; UIAccelerometer *accelerometer = [UIAccelerometer sharedAccelerometer]; accelerometer.updateInterval = 0.1; accelerometer.delegate = self; self.coef = 0.5; self.coefLabel.text = @"0.5"; }

12.1. Utiliser les acclromtres

373

4 Modiez le chier AcceleroViewController.h pour y dclarer les nouvelles proprits et la nouvelle mthode de la classe :
#import <UIKit/UIKit.h> @class VerticalView; @interface AcceleroViewController : UIViewController <UIAccelerometerDelegate> { IBOutlet UILabel * xLabel; IBOutlet UILabel * yLabel; IBOutlet UILabel * zLabel; IBOutlet UILabel * coefLabel; float coef; IBOutlet VerticalView * vert; } @property(nonatomic,retain) UILabel * xLabel; @property(nonatomic,retain) UILabel * yLabel; @property(nonatomic,retain) UILabel * zLabel; @property(nonatomic,retain) UILabel * coefLabel; @property(nonatomic,assign) float coef; @property(nonatomic,retain) VerticalView * vert; - (IBAction)changeCoef:(id)sender; @end

5 Modiez linterface utilisateur en ouvrant le chier AcceleroViewController.xib. Ajoutez un ascenseur et un label. Vriez que les valeurs de lascenseur sont comprises entre 0 et 1. Liez ces lments aux nouveaux outlets du propritaire du chier et liez lvnement Change Value de lascenseur laction changeCoef: du propritaire du chier. Vous pouvez maintenant construire lapplication et la tester sur votre appareil. Une faible valeur du coefficient, environ 0,1, diminue fortement les perturbations ; le repre graphique de la verticale ne tremble plus, et les deux premires dcimales des composantes de lacclration sont stables. Mais cette amlioration prsente un inconvnient : lors dun changement dorientation de lappareil, il faut plusieurs secondes pour que le segment reprsentant la verticale rallie sa nouvelle position. Apple recommande dutiliser un coefficient de 0,1. Si vous trouvez quavec cette valeur, lacclration calcule nest pas assez ractive, vous pouvez augmenter la frquence de mesure en modiant la valeur de la proprit updateInterval de lacclromtre. Les valeurs recommandes par Apple sont :
j

entre 0,05 et 0,1 pour connatre lorientation de lappareil ;

374

12. Acclromtres

entre 0,015 et 0,03 pour utiliser les mouvements de lappareil dans des jeux ; entre 0,01 et 0,015 pour mesurer des mouvements trs rapides, 0,01 est la valeur la plus faible admissible.

12.2. Dterminer les mouvements de lappareil


Le ltre passe-bas que nous venons dexprimenter permet de connatre lorientation de lappareil. Dans certains cas, on peut souhaiter que notre application ragisse aux changements dorientation. Physiquement, lapplication doit rechercher les modications dacclration, via un ltre passe-haut :
accelX = acc.x - ((acc.x * self.coef) (accelX* accelY = acc.y - ((acc.y * self.coef) (accelY* accelZ = acc.z - ((acc.z * self.coef) (accelY* + (1.0 - self.coef))); + (1.0 - self.coef))); + (1.0 - self.coef)));

Essayez ce ltre dans lapplication Accelero.


Souvenez-vous, vous avez galement la possibilit de dtecter les secousses en utilisant les vnements grs par lapplication. Reportez-vous pour cela au chapitre Tapes, touches et gestes.

12.3. Connatre lorientation de lappareil


Nous savons maintenant utiliser les acclromtres an de connatre la position relative de lappareil par rapport la verticale, ou pour en dterminer prcisment les mouvements. Dans la plupart des cas cependant, lapplication na pas besoin de ce niveau de dtail, elle a simplement besoin de connatre lorientation de lcran an dafficher les vues dans le "bon" sens.

12.3. Connatre lorientationde lappareil

375

Figure 12.6 : Orientation Portrait de lappareil

Figure 12.7 : Orientation Paysage de lappareil

376

12. Acclromtres

Retour sur la classe UIDevice


La classe UIDevice dispose dune proprit orientation lecture seule de type UIDeviceOrientation. La valeur de cette proprit donne lorientation de lappareil :
j j

UIDeviceOrientationUnknown, lorientation ne peut tre dtermine. UIDeviceOrientationPortrait, orientation Portrait bouton principal en bas. UIDeviceOrientationPortraitUpsideDown, orientation Portrait bouton principal en haut. UIDeviceOrientationLandscapeLeft, orientation Paysage bouton principal droite. UIDeviceOrientationLandscapeRight, orientation Paysage bouton principal gauche. UIDeviceOrientationFaceUp, lappareil est parallle au sol, lcran vers le haut. UIDeviceOrientationFaceDown, lappareil est parallle au sol, lcran vers le bas. Nous avons dj rencontr la classe UIDevice au chapitre Dessins et animations.

Lobtention de lorientation est trs simple. Il faut privilgier linstance unique de la classe UIDevice, puis activer lentretien de sa proprit orientation avant dobtenir sa valeur :
UIDevice *device = [UIDevice currentDevice]; [device beginGeneratingDeviceOrientationNotifications]; UIDeviceOrientation *orientation = device.orientation;

An dconomiser la batterie, il est recommand de dsactiver les acclromtres lorsque lapplication na pas besoin de connatre lorientation de lappareil :
[device endGeneratingDeviceOrientationNotifications];

Sabonner aux changements dorientation


Interroger linstance unique de la classe UIDevice est un moyen de connatre lorientation de lappareil. Il est parfois plus pratique dtre inform lors dun changement dorientation. Il faut pour cela sabonner aux notications UIDeviceOrientationDidChangeNotification mises par cette instance.

12.3. Connatre lorientationde lappareil

377

Dans ce cas aussi, il faut activer lmission des notications par le message beginGeneratingDeviceOrientationNotifications sur linstance unique de la classe UIDevice.
Reportez-vous au chapitre Persistance des donnes si vous avez oubli comment vous abonner une notication.

Orienter automatiquement les vues


Une fonctionnalit trs attrayante des logiciels sur iPhone est de voir linterface utilisateur suivre lorientation de lappareil. Cette fonctionnalit est facile obtenir ; nous allons la raliser avec notre application Accelero.

Figure 12.8 : Accelero en mode paysage

Obligatoire sur liPad


Sauf cas exceptionnel, vos applications pour iPad devront prendre en charge lorientation automatique des vues.

La prise en charge de lorientation automatique ncessite deux tapes :


j j

Le contrleur indique les orientations prises en charge. La taille et la position de chaque vue doivent tre dnies pour les orientations Portrait et Paysage.

378

12. Acclromtres

Autorotations prises en charge


Modiez la mthode shouldAutorotateToInterfaceOrientation: dans le chier AcceleroViewController.m :
- (BOOL)shouldAutorotateToInterfaceOrientation: (UIInterfaceOrientation)interfaceOrientation { return YES; }

Cette mthode est appele chaque changement dorientation de linterface. Elle doit retourner YES si lautorotation est prise en charge pour lorientation passe en paramtre. Par dfaut, la mthode dnie dans la classe UIViewController rpond YES pour lorientation Portrait UIDeviceOrientationPortrait, et NO pour les trois autres orientations de linterface. Nous rednissons cette mthode dans la classe AcceleroViewController pour quelle rponde YES pour toutes les orientations ; linterface utilisateur sera toujours oriente correctement quelle que soit la position de lappareil.

Orientation de lappareil et de linterface


Seules les quatre valeurs UIDeviceOrientationPortrait, UIDevice OrientationPortraitUpsideDown, UIDeviceOrientationLandscapeLeft et UIDeviceOrientationLandscapeRight peuvent tre utilises pour lorientation de linterface utilisateur.

Disposition des vues


1 Ouvrez le chier AcceleroViewController.xib sous Interface Builder. Le bouton en haut droite de la fentre de la vue principale permet de basculer la reprsentation de linterface entre le mode Portrait et le mode Paysage.

Figure 12.9 : Basculer la vue en mode Paysage

2 Cliquez sur le bouton de basculement pour voir ce que donnerait linterface en mode Paysage : le rsultat nest pas trs concluant. Les vues restent gauche de lcran, la partie droite nest pas utilise, et les vues du bas sortent de lcran. Nous aimerions

12.3. Connatre lorientationde lappareil

379

quen mode Paysage, les champs de texte indiquant les valeurs des composantes de lacclration restent gauche de lcran, et que la vue graphique ainsi que le rglage du ltre passent droite. 3 Revenez en mode Portrait et slectionnez les vues que vous souhaitez faire glisser sur la droite lorsque la vue principale basculera en mode Paysage.

Figure 12.10 : Slection suite au glisser droite en mode Paysage

4 Affichez linspecteur de taille, commande Size Inspector du menu Tools (X+[3]), et rglez les paramtres Autosizing de sorte que ces vues soient attaches par leurs bords droit et bas plutt que par leurs bords haut et gauche, ce qui est le dfaut.

Figure 12.11 : Attache des vues par leurs bords droit et bas

5 Basculez la vue principale en mode Paysage ; les vues du bas glissent vers la droite de lcran. Au besoin, ajustez la position et la taille de chacune des vues pour que leur disposition soit correcte aussi bien en mode Paysage quen mode Portrait.

380

12. Acclromtres

Les paramtres Autosizing fonctionnent de la faon suivante :


j

Il existe un attachement pour chacun des quatre bords de la vue, reprsent par un trait plein ou pointill : Un trait plein signie que la distance est xe entre le bord de la vue slectionn et le bord correspondant de sa super-vue. Un trait pointill signie quil ny a pas de contrainte de distance entre le bord de la vue slectionn et le bord correspondant de sa super-vue.

Il existe deux indicateurs de dimension, pour la hauteur et la largeur de la vue, reprsents par un trait plein ou pointill : Un trait pointill signie que la dimension est xe. Un trait plein signie que la dimension est variable en fonction de la dimension correspondante de sa super-vue.

En principe, si les attachements de bords opposs sont tous les deux en traits pleins, il faut que la dimension entre ces bords soit variable, donc galement en trait plein.

Pour que ces paramtres soient pris en compte, la case Autoresize Subviews doit tre coche dans linspecteur des attributs de la supervue, en loccurrence la vue principale, ce qui est le dfaut. 6 Reconstruisez lapplication sous XCode et vriez que linterface utilisateur suit lorientation de lappareil.

Challenge
En testant lapplication Accelero, vous remarquez que lindicateur graphique de verticale fonctionne uniquement en mode Portrait. Votre challenge sera de modier lapplication Accelero, et principalement la classe VerticalView pour quelle fonctionne pour les quatre orientations de linterface.

12.4. Checklist
Nous avons appris mettre en uvre les acclromtres pour dterminer la position de lappareil ou pour en dtecter les mouvements, et les classes et types concerns :
j j j

UIAccelerometer ; UIAccelerometerDelegate ; UIAcceleration ;

12.4. Checklist

381

UIAccelerationValue.

Nous avons vu comment utiliser la classe UIDevice, et son instance unique, pour connatre lorientation de lappareil et programmer les notications des changements dorientation. Nous savons doter nos applications de la fonctionnalit dautorotation de linterface utilisateur.

382

12. Acclromtres

SPCIFICITS DE LIPAD
Un SDK, deux cibles ................................................................................................ 385 Nouveauts de linterface visuelle .................................................................... 387 Reconnaissance des gestes .................................................................................. 396 Checklist ........................................................................................................................ 405

383

CHAPITRE 13

Vous disposez maintenant de connaissances suffisantes pour dvelopper vos propres applications, qui peuvent sexcuter de faon identique sur iPhone, iPod Touch et iPad. Certains ne voient dans liPad quun gros iPhone simplement moins pratique glisser dans la poche de son veston. Il est vrai que ces appareils mettent en uvre exactement les mmes technologies, avec pour liPad un cran plus large et une puissance et une autonomie accrues. LiPad ouvre un univers dapplications qui reste dfricher ; il lance une rvolution de linformatique mobile comparable ce que la musique a connu avec le baladeur MP3. la n de ce chapitre, vous connatrez les techniques spciques liPad qui vous permettront de crer vos applications, et pourquoi pas dtre un acteur de la rvolution en marche.

13.1. Un SDK, deux cibles


La version 3.2 du SDK de liPhone OS permet de dvelopper des applications pour des versions trs anciennes ; par exemple la version 2.0 distribue au printemps 2008. En principe, une application est produite pour la dernire version dOS disponible, mais il peut tre intressant daccrotre le nombre de ses clients en tendant la compatibilit de lapplication avec des versions dOS antrieures. La particularit introduite par liPad est la coexistence de deux "dernires" versions :
j j

La version 3.1.3 est la dernire version pour iPhone (et iPod Touch). La version 3.2 est la dernire version pour iPad (cest aussi la premire).

Tous les chapitres prcdents portent sur lutilisation du SDK 3.2 pour la production dapplications destines la version 3.1.3 : les applications iPhone capables de tourner sur iPad. Le prsent chapitre porte sur les spcicits de la version 3.2 : sur les applications spciquement ddies liPad.

Choisir sa cible de dploiement


Le plus simple pour choisir la cible de dploiement de lapplication (iPhone ou iPad) est de le prciser la cration du projet.

13.1. Un SDK, deux cibles

385

Figure 13.1 : Dnition de la cible de dploiement du projet

Si lon veut rednir la cible de dploiement sur un projet prexistant, on peut le faire dans la fentre dinformation de la cible du projet. Le tableau ci-aprs rsume les valeurs des paramtres de build en fonction de la cible de dploiement.

Figure 13.2 : Paramtres de la cible de dploiement


Tableau 13.1 : Valeurs des paramtres de build pour fixer la cible de dploiement Paramtre iPhone OS deployment target Targeted Device Family Base SDK Valeur pour iPhone Valeur pour iPad iPhone OS 3.1.3 iPhone iPhone Device 3.1.3 iPhone OS 3.2 iPad Valeur universelle iPhone OS 3.1.3 iPhone/iPad

iPhone Device 3.2 iPhone Device 3.2

386

13. Spcificits de liPad

La dernire colonne du tableau est intitule Valeur universelle. Une application iPhone OS est dite universelle lorsquelle sadapte lappareil sur lequel elle sexcute : iPhone ou iPad.

Crer une application universelle


Le plus simple pour crer une application universelle est de partir dun projet iPhone. 1 Ouvrez votre projet iPhone sous XCode et ouvrez le groupe Targets dans la partie gauche de la fentre, Groups & Files. 2 Cliquez du bouton droit sur la cible dsire pour ouvrir le menu contextuel et slectionnez la commande Upgrade Current Target for iPad. Une bote de dialogue souvre pour vous permettre dindiquer si vous souhaitez crer une application universelle unique (One Universal application) ou deux applications spciques (Two device-specic applications). Dans les deux cas, XCode va gnrer des chiers NIB pour iPad en dupliquant les chiers NIB du projet dans un dossier et dans un groupe Resources-iPad. Ainsi vous pouvez modier ces chiers pour particulariser linterface utilisateur chaque type dappareil. Dans le cas dune application universelle, il vous faudra crire du code qui sache sadapter lappareil. Dans le second cas, vous crirez deux applications dans le mme projet.

13.2. Nouveauts de linterface visuelle


La surface de lcran plus de quatre fois plus grande sur liPad ouvre des possibilits supplmentaires que nous allons examiner dans cette section. Il y sera question notamment des vues contextuelles (popover) et des vues scindes (splitview), deux des principales nouveauts de la version 3.2.

Recommandations gnrales
Autorotation de linterface
Commenons par une nouveaut qui nen est pas une. Nous avons vu au chapitre prcdent comment inclure lautorotation de linterface dans une application iPhone.

13.2. Nouveauts de linterface visuelle

387

Reportez-vous au chapitre Acclromtres si vous avez oubli comment grer lautorotation.

La "nouveaut" est que cette fonctionnalit doit tre systmatiquement incluse dans les applications pour iPad an de respecter les directives dApple concernant linterface utilisateur. Vous pouvez consulter ces directives dans le document iPad Human Interface Guidelines dApple.

Hirarchisation des donnes


La petite taille de lcran de liPhone ncessite un design particulier de linterface utilisateur, qui impose gnralement de structurer les donnes hirarchiquement. Cette hirarchisation est viter sur iPad dont lcran est plus grand que celui dun iPhone. Il faudra donc viter lutilisateur davoir naviguer entre plusieurs crans, lui donner le maximum dinformations et de possibilit sur un cran. Lapplication de type navigation, trs courante sur iPhone, est remplace par lapplication de type Vues Scindes (splitview) spcique liPad.

Figure 13.3 : Application de type vues scindes

On peut galement atteindre ce rsultat en regroupant le contenu de plusieurs crans dune application iPhone sur un seul cran dans lapplication quivalente sur iPad. Pensez aussi, lors du design de

388

13. Spcificits de liPad

linterface utilisateur, prsenter les informations dtailles ou les formulaires de saisie dans une vue contextuelle (popover).

Figure 13.4 : Utilisation dune vue contextuelle

Vues modales
Il y a deux diffrences dans la faon dont sont utilises les vues
modales entre liPhone et liPad :
j

Sur iPhone, une vue modale occupe tout lcran, ce nest pas forcment le cas sur iPad. Il ny a pas de limitation lemploi des vues modales sur iPhone ; les directives dApple en limitent lusage sur iPad.

Prsentation lcran
La proprit modalPresentationStyle de la classe UIViewController (dans la version 3.2 du SDK) permet de spcier la faon dont la vue modale doit tre prsente. Elle peut prendre les valeurs suivantes :
j

UIModalPresentationFullScreen, valeur par dfaut, prsentation de la vue modale en plein cran (comme sur liPhone) ; UIModalPresentationPageSheet, la vue modale occupe toute la hauteur de lcran, mais sa largeur est celle de la plus petite dimension de lcran (768 pixels sur iPad) ; UIModalPresentationFormSheet, la vue modale est plus petite que lcran et centre sur celui-ci ; UIModalPresentationCurrentContext, la vue modale utilise le mme style que sa vue parente.

Lors de laffichage dune vue modale, les parties de lcran non recouvertes par la vue sont grises et inaccessibles.

Usage des vues modales


Sur iPad, les vues modales doivent tre utilises exclusivement lorsque la tche en cours requiert lintervention de lutilisateur.

13.2. Nouveauts de linterface visuelle

389

Pour tous les autres usages, il est prfrable dutiliser les vues
contextuelles (popover), nouveaut de la version 3.2 :
j j j

prsenter une liste de slections ou dactions ; prsenter des informations dtailles ; prsenter une bote outils ou des options de conguration.

La diffrence essentielle entre une vue modale et une vue contextuelle porte sur le comportement lorsque lutilisateur touche lextrieur de la vue :
j

La premire interdit toute action lextrieur de la vue, qui est grise. La seconde est referme.

Vues contextuelles
Une vue contextuelle (popover) est prsente lcran avec une che pointant vers un bouton ou une autre vue.

Figure 13.5 : Exemple de vue contextuelle

Prparer une vue contextuelle


Deux contrleurs de vue sont mis en jeu :
j

le

contrleur

de

vue

contextuel,

instance

de

la

classe

UIPopoverController, charg de grer le contenant de la vue contex-

tuelle ;
j

un contrleur de vue quelconque, dont la classe drive de


UIViewController, charg de grer le contenu de la vue contex-

tuelle. Le contrleur du contenu est prpar de la mme faon, quelle que soit la manire dont il sera affich : dans une vue contextuelle, une vue modale, une pile de navigation, etc. Une spcicit toutefois, la taille du contenu de la vue contextuelle doit tre spcie dans la proprit contentSizeForViewInPopover de son contrleur, par exemple :

390

13. Spcificits de liPad

contentViewController.contentSizeForViewInPopover = CGSizeMake(320.0, 110.0);

Limitation de la taille
La largeur du contenu dune vue contextuelle doit tre comprise entre 320 et 600 pixels. Sa hauteur est libre.

Afficher une vue contextuelle


Le contrleur du contenu est associ au contrleur du contenant la cration de ce dernier :
UIPopoverController* aPopover = [[UIPopoverController alloc] initWithContentViewController:contentViewController];

Lors de sa prsentation lcran, il faut prciser lobjet sur lequel doit pointer la che de la vue contextuelle ainsi que les directions autorises. On utilise deux mthodes diffrentes suivant que la vue est associe un bouton de barre doutils (UIBarButtonItem) ou plus gnralement un rectangle dans une vue :
j

presentPopoverFromBarButtonItem:permittedArrowDirections:animated: pour associer la vue un bouton ; presentPopoverFromRect:inView:permittedArrowDirections:animated: dans le cas gnral.

Le paramtre permittedArrowDirections permet de prciser quelles directions sont autorises pour la che de la vue contextuelle :
j j j j

UIPopoverArrowDirectionUp autorise une che vers le haut. UIPopoverArrowDirectionDown autorise une che vers le bas. UIPopoverArrowDirectionLeft autorise une che vers la gauche. UIPopoverArrowDirectionRight autorise une che vers la droite.

Ces valeurs peuvent tre combines par loprateur | an dautoriser plusieurs directions. La valeur UIPopoverArrowDirectionAny peut galement tre utilise pour autoriser la che dans toutes les directions.

Refermer une vue contextuelle


Lorsque lutilisateur touche lextrieur dune vue contextuelle, cette dernire est automatiquement referme. Le dlgu du contrleur de la vue contextuelle en est inform ; il peut bloquer la fermeture au besoin.

13.2. Nouveauts de linterface visuelle

391

On peut galement refermer la vue contextuelle en transmettant le message dismissPopoverAnimated: son contrleur.

Dlgu de vue contextuelle


Le dlgu du contrleur de vue contextuelle, non obligatoire, rpond au protocole UIPopoverControllerDelegate. Il reoit le message popoverControllerShouldDismissPopover: lorsque lutilisateur touche lextrieur de la vue. Il doit retourner YES pour autoriser sa fermeture (valeur par dfaut). Lorsque la vue contextuelle est effectivement referme, son dlgu reoit le message
popoverControllerDidDismissPopover:.

Vues scindes
Les vues scindes (splitview) concernent un mode dutilisation de lcran de liPad :
j

En mode Paysage, lcran est scind en deux, une vue est affiche dans la partie gauche, dune largeur de 320 pixels, et une seconde vue occupe lautre partie de lcran. En mode Portrait, seule la partie droite est affiche, la partie gauche peut tre visualise dans une vue contextuelle.

Figure 13.6 : Vue scinde en mode Paysage

392

13. Spcificits de liPad

Figure 13.7 : Vue scinde en mode Portrait

Contrleur de vue scinde


Le contrleur de vue scinde, instance de la classe UISplitViewController, doit tre le contrleur racine de la fentre. Il ne peut tre inclus dans un autre contrleur de vue. Il prend en charge le comportement de la vue lors des changements dorientation de linterface utilisateur. Cette classe prsente seulement deux proprits :
j

viewControllers, tableau contenant les deux contrleurs de vue associs la vue scinde, dans lordre la vue de gauche puis la vue de droite ; delegate, le dlgu de vue scinde qui est inform des changements dorientation de linterface utilisateur.

Dlgu du contrleur de vue scinde


Le dlgu du contrleur de vue scinde rpond au protocole UISplitViewControllerDelegate. Il reoit un message splitView Controller:willHideViewController:withBarButtonItem:forPopover Controller: lorsque lappareil passe en mode Portrait et que la vue de gauche va tre masque. Ce message contient notamment un bouton de barre doutils prpar par le contrleur de vue scinde. Il appartient au dlgu dafficher ce bouton qui permettra lutilisateur de voir le contenu de la vue de gauche dans une vue contextuelle. Par exemple, pour afficher ce bouton gauche dune barre doutils tout en lui donnant un titre :

13.2. Nouveauts de linterface visuelle

393

- (void)splitViewController:(UISplitViewController*)svc willHideViewController:(UIViewController *)aViewController withBarButtonItem:(UIBarButtonItem*)barButtonItem forPopoverController: (UIPopoverController*)pc { barButtonItem.title = @"Objets prts"; NSMutableArray *items = [[toolbar items] mutableCopy]; [items insertObject:barButtonItem atIndex:0]; [toolbar setItems:items animated:YES]; [items release]; }

linverse, le message splitViewController:willShowViewController: invalidatingBarButtonItem: est reu par le dlgu du contrleur de vue scinde lorsque lappareil passe en mode Paysage. Il faut alors retirer le bouton prcdent :
- (void)splitViewController: (UISplitViewController*)svc willShowViewController:(UIViewController *)aViewController invalidatingBarButtonItem:(UIBarButtonItem *)barButtonItem { NSMutableArray *items = [[toolbar items] mutableCopy]; [items removeObjectAtIndex:0]; [toolbar setItems:items animated:YES]; [items release]; }

Le dernier message susceptible dtre reu par le dlgu du contrleur de vue scinde est splitViewController:popoverController: willPresentViewController:, en mode Portrait lorsque la vue contextuelle contenant la vue de gauche est sur le point dtre affiche.

Application de type Vue scinde


Le plus simple pour utiliser les vues scindes est de crer sous XCode une application de type Vue scinde.

Figure 13.8 : Cration dune application de type Vue scinde

394

13. Spcificits de liPad

Nous disposons alors dun chier MainWindow.xib appartenant lapplication et qui contient :
j j

le dlgu dapplication, classique ; un contrleur de vue scind dont : la vue de gauche est un contrleur de navigation dont la vue principale est un contrleur de vue en table RootViewController ; la vue de droite est dcrite dans le chier DetailView.xib et son contrleur est DetailViewController.

La vue dtaille prpare dans le chier DetailView.xib offre une barre doutils qui contiendra le bouton permettant de voir la vue de gauche en mode Portrait. Le contrleur de la vue dtaille DetailView Controller est le dlgu de la vue scinde ; cest lui qui gre le bouton de visualisation de la vue gauche en mode Portrait.

Figure 13.9 : Contenu du chier MainWindow.xib

Figure 13.10 : Contenu du chier DetailView.xib

13.2. Nouveauts de linterface visuelle

395

Challenge
Rcrivez lapplication Emprunts sous forme de vue scinde pour iPad. Souvenez-vous quil nest pas utile de hirarchiser les donnes pour les manipuler sur iPad.

13.3. Reconnaissance des gestes


Vous savez dj comment interprter les vnements reus par une vue pour reconnatre les gestes effectus par lutilisateur.
Reportez-vous au chapitre Tapes, touches et gestes si vous avez besoin de vous rafrachir la mmoire au sujet de la gestion des vnements et la reconnaissance des gestes sur iPhone.

La version 3.2 permet heureusement de simplier grandement la reconnaissance des gestes. Il suffit maintenant de programmer une cible-action sur un ou plusieurs analyseurs de geste, puis dattacher ces dernier la vue. Cest une bonne nouvelle, vous navez plus besoin de driver la classe UIView ni dcrire le code pour la reconnaissance des gestes, sauf bien sr si vous voulez dvelopper vos propres analyseurs.

Gestes de base
Un analyseur de geste est une instance dune classe drive de UIGestureRecognizer. En effet, cette classe est une classe abstraite qui implmente les mcanismes fondamentaux pour la reconnaissance des gestes. Chaque geste particulier est reconnu par une classe concrte qui drive de UIGestureRecognizer. Un analyseur est programm pour reconnatre un geste particulier. Lorsque ce geste est reconnu, lanalyseur dlivre une notication par le mcanisme cible-action ; plusieurs cibles-actions peuvent tre programmes sur chaque analyseur.

Modes de fonctionnement
Certains analyseurs fonctionnent de faon discrte ; une notication vers chaque cible est mise lorsque le geste est reconnu, puis lanalyseur est remis zro pour attendre le geste suivant. Dautres fonctionnent de faon continue ; ils dlivrent une srie de notications qui dbute quand le geste est reconnu et dure tant quil est maintenu.

396

13. Spcificits de liPad

Analyseurs discrets
j

Un analyseur de la classe UITapGestureRecognizer reconnat les tapes, simples ou multiples avec un ou plusieurs doigts. Lanalyseur est programm pour un nombre de tapes et un nombre de doigts dnis.

Un analyseur de la classe UISwipeGestureRecognizer reconnat les glissements. Il est programm pour reconnatre un geste dans une ou plusieurs des quatre directions et avec un nombre de doigts prdtermins.

Analyseurs continus
j

Un analyseur de la classe UIPinchGestureRecognizer reconnat les pincements ; rapprochement ou loignement de deux doigts sur lcran. Lanalyseur peut tre interrog sur le taux et la vitesse dloignement des deux doigts.

Un analyseur de la classe UIPanGestureRecognizer reconnat les dplacements libres sur lcran dun ou plusieurs doigts. Lanalyseur est programm pour un minimum et un maximum de touches simultanes. Il dlivre le vecteur et la vitesse de dplacement. Un analyseur de la classe UIRotationGestureRecognizer reconnat les rotations avec deux doigts. Lanalyseur peut tre interrog sur la valeur et la vitesse de rotation. Un analyseur de la classe UILongPressGestureRecognizer reconnat les appuis prolongs. Lanalyseur est programm pour un nombre de tapes (une par dfaut), un nombre de doigts (un par dfaut), une dure minimale (0,4 secondes par dfaut) et un dplacement maximal (10 pixels).

Classe UIGestureRecognizer
La mthode initWithTarget:action: est dnie dans la classe abstraite UIGestureRecognizer. Elle doit tre applique la cration dune instance de classe concrte pour associer lanalyseur un couple cible-action. Le slecteur pass en paramtre doit rpondre la signature standard dune action ; il peut recevoir un paramtre qui est lmetteur de laction (sender). Des exemples de code seront donns plus loin. Lmetteur de laction peut tre utilis par la cible pour connatre les caractristiques du geste qui vient dtre reconnu ; en particulier, lemplacement du geste dans la vue qui est rendu par lune des deux mthodes :

13.3. Reconnaissance des gestes

397

j j

locationInView: ; locationOfTouch:inView: pour connatre lemplacement dune touche particulire.

La proprit numberOfTouches permet de connatre le nombre de touches du geste, et la proprit enabled, de type BOOL et dont laccesseur est isEnabled, permet dautoriser ou pas le fonctionnement de lanalyseur (il est autoris par dfaut).

Proprits particulires chaque geste


Pour chaque classe concrte drive de UIGestureRecognizer, les proprits et mthodes permettant de programmer lanalyseur (P) ou dobtenir les caractristiques du geste reconnu (C) sont rsumes dans le tableau ci-aprs
Tableau 13.2 : Proprits et mthodes des analyseurs de geste Analyseur concret Proprit ou mthode P/C Usage P P C C P P Nombre de tapes requis pour reconnatre le geste (1 par dfaut) Nombre de doigts requis pour reconnatre le geste (1 par dfaut) Facteur de pincement Vlocit en facteur dchelle par seconde Nombre maximum de doigts requis pour reconnatre le geste Nombre minimum de doigts requis pour reconnatre le geste (1 par dfaut) Dplacement du doigt dans les coordonnes de la vue passe en paramtre Vitesse de dplacement du doigt dans les coordonnes de la vue passe en paramtre Direction du dplacement pour reconnatre le geste Nombre de doigts requis pour reconnatre le geste (1 par dfaut)

UITapGesture Recognizer

NSUInteger number OfTaps Required NSUInteger number OfTouches Required

UIPinch Gesture Recognizer UIPanGesture Recognizer

CGFloat scale CGFloat velocity NSUInteger maximum Number OfTouches NSUInteger minimum Number OfTouches (CGPoint) translationInView: (UIView *)view

(CGPoint )velocity C InView: (UIView *)view UISwipe Gesture Recognizer UISwipeGesture P RecognizerDirection direction NSUInteger number OfTouches Required
P

398

13. Spcificits de liPad

Tableau 13.2 : Proprits et mthodes des analyseurs de geste Analyseur concret Proprit ou mthode P/C Usage C C P Rotation en radians depuis le dernier message Vitesse de rotation en radians/seconde Dure minimale de la touche (dfaut 0,4 s) Nombre de doigts requis pour reconnatre le geste (1 par dfaut) Nombre de tapes requis pour reconnatre le geste (1 par dfaut) Dplacement maximum pour reconnatre le geste (dfaut 10 pixels)

UIRotation Gesture Recognizer UILongPress Gesture Recognizer

CGFloat rotation CGFloat velocity CFTimeInterval minimumPress Duration NSInteger number OfTouches Required NSUInteger number OfTaps Required CGFloat allowable Movement

UISwipeGestureRecognizerDirection est un type numr qui admet les constantes suivantes :


j j j j

UISwipeGestureRecognizerDirectionRight, glissement vers la droite ; UISwipeGestureRecognizerDirectionLeft, glissement vers la gauche ; UISwipeGestureRecognizerDirectionUp, glissement vers le haut ; UISwipeGestureRecognizerDirectionDown, glissement vers le bas.

Ces valeurs peuvent tre combines par loprateur | pour autoriser la reconnaissance du geste selon plusieurs directions.

Utiliser un analyseur de geste


Nous allons illustrer le fonctionnement des analyseurs de geste par la mise en uvre dun analyseur de pincement (continu) et dun analyseur de tapes (discret).

Crer linterface utilisateur


1 Crez une application pour iPad base sur une vue (View-based application) intitule AnalyseurDeGeste. Ouvrez le chier AnalyseurDeGesteViewController.xib et placez trois labels et trois champs de texte.

13.3. Reconnaissance des gestes

399

Figure 13.11 : Interface de lanalyseur de geste

2 Crez les outlets pour les champs de texte dans linterface du contrleur de vue dans le chier AnalyseurDeGesteViewController.h. Protez-en pour ajouter une variable dinstance an de compter les tapes simples et doubles et pour rendre compte du pincement :
@interface AnalyseurDeGesteViewController : UIViewController { IBOutlet UITextField *scaleField; IBOutlet UITextField *simpleTaps; IBOutlet UITextField *doubleTaps; CGFloat scale; NSUInteger simpleTapCounter; NSUInteger doubleTapCounter; } @property(retain,nonatomic) UITextField *scaleField; @property(retain,nonatomic) UITextField *simpleTaps; @property(retain,nonatomic) UITextField *doubleTaps; @end

3 Effectuez les liens entre les outlets et les champs de texte sous Interface Builder.

Mettre en uvre les analyseurs


Les analyseurs de geste communiquent par le mcanisme cibleaction lorsquils reconnaissent un geste. Ajoutez une action dans le contrleur de vue pour chaque geste que nous souhaitons dtecter (simple tape, double tape et pincement) :
@interface AnalyseurDeGesteViewController : UIViewController { IBOutlet UITextField *scaleField; IBOutlet UITextField *simpleTaps; IBOutlet UITextField *doubleTaps; CGFloat scale; NSUInteger simpleTapCounter; NSUInteger doubleTapCounter; } @property(retain,nonatomic) UITextField *scaleField; @property(retain,nonatomic) UITextField *simpleTaps;

400

13. Spcificits de liPad

@property(retain,nonatomic) UITextField *doubleTaps; - (IBAction) scaleChange:(UIGestureRecognizer *)sender; - (IBAction) simpleTap; - (IBAction) doubleTap; @end

Nous allons maintenant crire le code pour mettre en uvre les analyseurs.

Analyseur de tapes
La mthode initWithTarget:action: dnie dans la classe mre de tous les analyseurs de geste (UIGestureRecognizer) permet didentier le couple cible-action actionner la reconnaissance du geste. Par exemple, pour lanalyseur de tape simple :
UITapGestureRecognizer *simpleTapRecognizer ; simpleTapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(simpleTap)];

Ensuite, il faut programmer lanalyseur en utilisant ses proprits. Pour un analyseur de tapes, les proprits sont :
j j

numberOfTapsRequired, nombre de tapes requises ; numberOfTouchesRequired, nombre de doigts requis.

Enn, la mthode addGestureRecognizer: dnie dans UIView permet dattacher des analyseurs de geste une vue. On peut ensuite librer la rfrence lanalyseur car elle est retenue par la vue :
[self.view addGestureRecognizer:simpleTapRecognizer]; [simpleTapRecognizer release];

Dans notre application, la rception des tape simples et doubles va simplement incrmenter leur compteur respectif. Saisissez le code des actions dans le chier AnalyseurDeGesteViewController.m :
- (IBAction) simpleTap{ simpleTapCounter++; simpleTaps.text = [NSString stringWithFormat:@"%d",simpleTapCounter]; } - (IBAction) doubleTap{ doubleTapCounter++; doubleTaps.text = [NSString stringWithFormat:@"%d",doubleTapCounter]; }

Analyseur de pincement
Lanalyseur de pincement est encore plus simple crer car il ne se programme pas :

13.3. Reconnaissance des gestes

401

UIPinchGestureRecognizer *pinchRecognizer ; pinchRecognizer = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:@selector(scaleChange:)]; [self.view addGestureRecognizer:pinchRecognizer]; [pinchRecognizer release];

Nous utilisons ici un slecteur dont le nom nit par deux points pour indiquer quil faut lui passer lmetteur de laction (sender) en paramtre lors de la notication. Ainsi nous pourrons interroger lanalyseur sur les caractristiques du geste, ce qui tait inutile avec les tapes qui nont pas de caractristique particulire. Laction connecte au pincement affiche le facteur dchelle lcran. Saisissez le code de laction dans le chier AnalyseurDeGesteViewController.m :
- (IBAction) scaleChange:(UIGestureRecognizer *)sender{ scale = 100.*[(UIPinchGestureRecognizer *)sender scale]; scaleField.text=[NSString stringWithFormat:@"%f",scale]; }

Initialiser lapplication
Le code pour initialiser les analyseurs de geste doit tre insr dans la mthode viewDidLoad du contrleur de vue. Cette mthode contient aussi le code pour initialiser les champs de texte et les variables dinstances. Saisissez ce code dans le chier AnalyseurDeGesteViewController.m :
- (void)viewDidLoad { [super viewDidLoad]; // Create and configure the Pinch recognizer UIPinchGestureRecognizer *pinchRecognizer ; pinchRecognizer = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:@selector(scaleChange:)]; [self.view addGestureRecognizer:pinchRecognizer]; // Create and configure the Double Tap recognizer UITapGestureRecognizer *doubleTapRecognizer ; doubleTapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(doubleTap)]; doubleTapRecognizer.numberOfTapsRequired = 2; doubleTapRecognizer.numberOfTouchesRequired = 1; [self.view addGestureRecognizer:doubleTapRecognizer]; // Create and configure the Simple Tap recognizer UITapGestureRecognizer *simpleTapRecognizer ; simpleTapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(simpleTap)]; simpleTapRecognizer.numberOfTapsRequired = 1; simpleTapRecognizer.numberOfTouchesRequired = 1; [self.view addGestureRecognizer:simpleTapRecognizer]; // Release the Gesture Recognizers [pinchRecognizer release];

402

13. Spcificits de liPad

[doubleTapRecognizer release]; [simpleTapRecognizer release]; // Counters initialization scale = 100.; simpleTapCounter = 0; doubleTapCounter = 0; // Text Field initialization scaleField.text = [NSString stringWithFormat:@"%f",scale]; simpleTaps.text = [NSString stringWithFormat:@"%d",simpleTapCounter]; doubleTaps.text = [NSString stringWithFormat:@"%d",doubleTapCounter]; }

Compltez le code du contrleur de vue avec la synthse des accesseurs des proprits, construisez lapplication et testez-la.

Amliorer le comportement
Lorsque vous testez lapplication, vous constatez que deux tapes rapproches sont comptabilises deux fois :
j j

La premire tape est compte comme une tape simple. La seconde est compte comme la deuxime tape dune tape double ; elle nest pas compte comme une tape simple.

Lanalyseur de tape double ayant reconnu un geste, une notication est mise par le mcanisme cible-action, et lanalyse des gestes est interrompue ; cest le comportement par dfaut. Dans certains cas, il est souhaitable de retarder la reconnaissance de la tape simple ; attendre lventualit dune deuxime tape pour dterminer sil sagit dune tape simple ou double. La mthode requireGestureRecognizerToFail: permet de demander au rcepteur du message de notier la reconnaissance du geste uniquement si lanalyseur pass en paramtre dclare quil na pas reconnu son geste. Pour viter que la premire tape dune tape double ne soit interprte comme une tape simple, ajoutez la ligne de code suivante dans la mthode viewDidLoad :
[simpleTapRecognizer requireGestureRecognizerToFail:doubleTapRecognizer];

Challenge
Compltez lapplication AnalyseurDeGeste pour tester tous les gestes proposs par la version 3.2 du SDK.

13.3. Reconnaissance des gestes

403

Synchroniser les analyseurs


Dans la version 3.2, les vnements de touches sont transmis simultanment la vue et aux ventuels analyseurs de geste qui lui sont attachs. Les analyseurs de geste sont trs faciles utiliser, le seul point dlicat est leur synchronisation lorsque plusieurs sont attachs la mme vue. Un seul geste est reconnu lorsquun vnement est reu par la vue, le premier analyseur qui dclenche une action bloque tous les autres, le problme est que lon ne sait pas lequel est "le premier". Par exemple si lon programme simultanment un analyseur de tape pour une tape simple et un second pour une tape double, une tape double peut dclencher, en fonction de lanalyseur qui est "le premier" :
j j

soit la notication dune tape simple puis dune tape double ; soit la notication de deux tapes simples.

Le dveloppeur dispose de plusieurs moyens pour synchroniser le fonctionnement des analyseurs de geste :
j

La proprit enabled permet de bloquer ou dactiver le fonctionnement dun analyseur. La mthode requireGestureRecognizerToFail:, que nous venons dutiliser, permet de dnir la priorit entre deux analyseurs. Lun des dlgus de deux analyseurs peut permettre quils mettent une notication simultane, au lieu que lun bloque lautre comme dans le fonctionnement par dfaut. Le dlgu dun analyseur peut bloquer temporairement sont fonctionnement.

Dlgu danalyseur
Chaque analyseur dispose dune proprit delegate qui rfrence son ventuel dlgu. Ce dernier doit rpondre au protocole UIGesture RecognizerDelegate qui dclare les trois mthodes suivantes :
j

gestureRecognizerShouldBegin: est appele lorsque lanalyseur est sur le point de commencer lanalyse dun geste. Elle doit retourner YES (valeur par dfaut) si lanalyseur est autoris dbuter lanalyse. Si elle rpond NO, lanalyse est interrompue. gestureRecognizer:shouldReceiveTouch: est appele avant quun vnement de touche ne soit transmis lanalyseur. Elle doit

404

13. Spcificits de liPad

retourner YES (valeur par dfaut) pour autoriser la transmission et NO pour linterdire. gestureRecognizer:shouldRecognizeSimultaneouslyWithGesture Recognizer: est appele lorsque deux analyseurs sont sur le point de reconnatre simultanment un geste. La simultanit est autorise si lun des dlgus rpond YES. NO est la valeur par dfaut.

13.4. Checklist
Nous avons explor dans ce chapitre les spcicits du dveloppement dapplications pour iPad concernant linterface utilisateur. Nous avons commenc par les rglages des paramtres de XCode pour slectionner la cible des applications : iPhone ou iPad. Concernant laspect visuel, nous savons maintenant :
j

que lutilisation des vues modales est limite des cas trs particuliers et que lon peut modier leur aspect visuel avec la proprit modalPresentationStyle ; que pour les autres usages, il faut prfrer les Vues contextuelles (popover) avec la mise en uvre du contrleur UIPopoverController et de son dlgu UIPopoverControllerDelegate ; que les applications de type Vue scinde (splitview) sont prfrer la navigation hirarchique, avec la mise en uvre du contrleur UISplitViewController et de son dlgu UISplit ViewController Delegate.

Concernant la gestion des vnements de touche, nous avons examin le fonctionnement et lutilisation des analyseurs de geste (gesture recognizer).

13.4. Checklist

405

ANNEXE

pilogue ......................................................................................................................... 409 Politique dApple ....................................................................................................... 409 Processus de diffusion ............................................................................................ 412

407

CHAPITRE 14

14.1. pilogue
Nous avons explor dans cet ouvrage les principaux frameworks permettant de mettre en uvre les possibilits de liPhone, de liPod Touch et de liPad, en nous concentrant sur celles qui rendent ces appareils si attrayants : cran multi Touch, acclromtres, capteur magntique. Nous vous laissons explorer par vous-mme, en fonction de vos besoins, les technologies plus classiques, par exemple celles lies la connectivit, puis celles plus avances (scurit, debugger, tests automatiques, etc.). Certaines de ces technologies sont disponibles sur iPhone et iPad, dautres sont spciques ce dernier :
j j j j

possibilit lmentaire de communication de chiers ; production de documents PDF ; gestion amliore des polices de caractres ; possibilit dadapter la saisie de texte, etc.

La documentation dApple est trs bien faite et les forums de dveloppeurs francophones vous seront dune aide prcieuse : par exemple http://forum.macbidouille.com ou http://www.pommedev.com. Nous vous souhaitons un parcours rempli de dcouvertes et de succs.

14.2. Politique dApple


La suite de cette annexe est consacre la description de la politique dApple concernant les dveloppeurs pour iPhone et aux processus de diffusion des applications. Apple pouvant tout moment modier ces conditions, les informations contenues dans cette annexe sont fournies titre purement indicatif.

Les diffrents statuts de dveloppeur


Apple a dni trois niveaux de dveloppeur :
j

dveloppeur enregistr (Registered iPhone Developer) qui permet :

de tlcharger le SDK ; daccder la documentation Apple ; de tester ses applications avec le simulateur diPhone.

14.2. Politique dApple

409

quipe de dveloppement inscrite au programme iPhone (iPhone


Developer Program) qui permet :

de tester ses application sur des appareils rels ; de diffuser ses applications de faon limite ; daccder aux versions Bta diPhone OS et du SDK.
j

quipe de dveloppement inscrite au programme iTunes (iTunes


Connect) qui permet :

de diffuser ses applications sur lAppStore ; de percevoir des revenus. Le tableau ci-aprs rsume les conditions associes ces diffrents statuts.
Tableau 14.1 : Conditions associes aux diffrents statuts Niveau Enregistr Programme Standard Programme Entreprise Programme iTunes Cot 0 99 $ par an (79 5) 299 $ par an (239 5) 0 Objectif Dvelopper sur simulateur Tester ou diffuser sur 100 appareils Diffuser en interne dans lentreprise Diffuser sur lApp Store Condition tre enregistr tre enregistr et tre une socit de plus de 500 personnes Avoir adhr au programme standard

Programme Entreprise
Ce programme ne permet pas de diffuser sur lAppStore. Il est utile uniquement pour les grandes organisations souhaitant dvelopper des applications spciques usage interne.

Programme Standard
Ce programme est ouvert aux personnes physiques et aux personnes morales (entreprises). Une quipe de plusieurs personnes peut adhrer ce programme.

Diffusion des applications


Il existe trois faons de diffuser son application :
j

diffusion prive sur un maximum de 100 appareils rfrencs, qui ncessite ladhsion au programme Standard ;

410

14. Annexe

diffusion prive sur plus de 500 appareils, qui ncessite ladhsion au programme Entreprise ; diffusion au grand public sur lAppStore, qui ncessite ladhsion au programme Standard et liTunes Connect.

Diffusion des applications


La politique dApple interdit tout autre mode de diffusion.

Une application peut tre mise en diffusion gratuite ou payante sur lAppStore, au choix du responsable de lquipe de dveloppement :
j j

Le prix de lapplication est dni par le responsable de lquipe. 70 % du prix des ventes est revers mensuellement lquipe de dveloppement par Apple. Cette marge de 30 % prise par Apple intgre tous les services fournis par lAppStore : frais de paiement par carte de crdit ; hbergement sur le site dApple ; marketing.

Les applications gratuites sont diffuses gratuitement sur lAppStore.

Signature du code
Le code qui sexcute sur un appareil rel doit obligatoirement tre sign par ladhrent au programme iTunes Connect. Cette signaturepermet Apple de contrler la diffusion des applications, puisquil faut passer par le programme Standard pour obtenir les certicats permettant de signer le code. Elle permet surtout aux utilisateurs dtre certains de lorigine des applications quils utilisent ; elle est garantie par Apple. Sans cette prcaution, un appareil minemment communiquant tel que liPhone, et dans une moindre mesure liPod Touch, deviendraient trs sensibles aux attaques malveillantes. Apple a prvu trois types de signature en fonction de la destination du code :
j

le test des applications sur des appareils rels ; le dveloppeur doit les installer lui-mme partir de XCode ;

14.2. Politique dApple

411

la diffusion limite (diffusion ad hoc) ; les applications peuvent tre transmises aux possesseurs des appareils rfrencs ; la diffusion publique, sur lAppStore.

La signature est ralise sous XCode par le dveloppeur (pour le test) ou par le responsable de lquipe de dveloppement (pour la diffusion). Elle ncessite :
j

la possession dun certicat qui identie le dveloppeur ou le responsable de lquipe ; ce certicat est fourni par Apple et permet dassurer aux utilisateurs que lapplication a t ralise par lquipe identie ; lidentication de lapplication ; pour les tests et les diffusions limites, lidentication des appareils autoriss.

j j

Certicats
La personne qui sinscrit un programme de dveloppeur, Standard ou Entreprise, est considre par Apple comme le reprsentant et responsable de lquipe de dveloppement. Chaque membre de lquipe doit tre un dveloppeur enregistr sur le site des dveloppeurs dApple an de pouvoir tlcharger le SDK et accder la documentation sur le site. Le responsable de lquipe est nomm Agent. Une quipe de dveloppement ne peut avoir quun seul agent ; il dclare les identiants dapplication et a le droit de les diffuser. Il cumule galement les privilges attachs aux administrateurs. Un administrateur gre les dveloppeurs (il autorise leur certication) et le parc dappareils. Il peut y avoir plusieurs administrateurs dans une quipe de dveloppement. Ils sont nomms par lagent. Un simple membre peut demander un certicat personnel. Une fois quil la obtenu, il peut signer les applications quil produit pour les tester sur des appareils rels.

14.3. Processus de diffusion


Apple pouvant tout moment modier le site des dveloppeurs, les copies dcrans et le processus dcrits dans cette section sont fournis titre purement indicatif.

412

14. Annexe

Senregistrer comme dveloppeur


Chaque personne physique qui souhaite parcourir le site des dveloppeurs doit y tre enregistre : http://developer.apple.com/iphone.

Figure 14.1 : Enregistrement sur le site des dveloppeurs sur iPhone

Lidentiant et le mot de passe sont personnels et ne doivent pas tre communiqus, sauf aux mineurs de 13 17 ans qui peuvent utiliser ceux dun de leurs reprsentants lgaux. Un dveloppeur enregistr na pas le droit de divulguer les informations condentielles auxquelles il a accs sur le site des dveloppeurs : les informations relatives aux versions Bta et les informations payantes sont condentielles. Si vous tes personnellement dj enregistr sur lun des sites dApple, par exemple sur liTunes Store ou sur le service Mobile Me, vous pouvez utiliser le mme identiant pour vous enregistrer comme dveloppeur. Il est gnralement conseill davoir des identiants spars pour lusage priv (acheter de la musique sur liTunes Store, par exemple) et pour lusage professionnel ou semi professionnel ; vendre des applications sur lAppStore.

Sinscrire au programme des dveloppeurs


Cration dun compte
Vous pouvez adhrer au programme des dveloppeurs soit titre individuel, soit comme reprsentant dune personne morale et dune

14.3. Processus de diffusion

413

quipe de dveloppement. Dans ce dernier cas, la personne physique qui sinscrit au programme des dveloppeurs doit avoir la capacit dengager son organisation. Elle sera considre comme responsable de lquipe de dveloppement par Apple, appele Agent du programme pour lorganisation. La personne qui adhre au programme des dveloppeurs doit pralablement tre enregistre sur le site des dveloppeurs. Apple propose le programme Standard et le programme Entreprise. Le programme Standard correspond la majorit des usages ; il donne ensuite accs la diffusion sur lAppStore.

Figure 14.2 : Inscription au programme des dveloppeurs

Administration du compte
Une fois linscription au programme Standard ralise, lagent et les ventuels administrateurs grent le compte laide des portails web prvus cet effet :
j

le centre des membres (Member Center) pour grer la composition de lquipe ; le portail des autorisations (iPhone Provisioning Portal) pour grer les certicats.

414

14. Annexe

Figure 14.3 : Accs aux portails du programme des dveloppeurs

Centre des membres


La page People du centre des membres permet aux administrateurs de grer les membres de lquipe.

Figure 14.4 : Accs la gestion des membres de lquipe

14.3. Processus de diffusion

415

Ils ont la possibilit dinviter une ou plusieurs personnes rejoindre lquipe en fournissant pour chacune :
j j j j

son prnom ; son nom ; son adresse de courriel ; son rle, administrateur (Admin) ou membre (Member).

Si vous souhaitez inviter un dveloppeur dans votre quipe, saisissez les renseignements demands et cliquez sur le bouton Send Invitation pour envoyer linvitation.

Figure 14.5 : Invitation dun nouveau membre

Chaque personne invite reoit un courriel lui proposant de senregistrer comme dveloppeur et de rejoindre lquipe. Lorsquil aura accept linvitation, il pourra accder au portail du programme avec son propre identiant.

Portail des autorisations


Le bandeau gauche de la page principale du portail permet daccder ses diffrentes fonctions :
j

Certicates ; gestion des certicats des membres de lquipe de dveloppement et des certicats de distribution pour lagent du compte ; Devices ; gestion des appareils de test ou pour la diffusion limite des applications. Le nombre dappareils est limit 100 par an au total (test et diffusion, tout type dappareil confondu) ; App IDs ; gestion des identiants pour les applications ;

416

14. Annexe

Provisioning ; gestion des chiers de Provisioning, ces chiers permettent la signature et lexcution du code ; Distribution ; informations pour la distribution et accs au portail de liTunes Connect.

Figure 14.6 : Page principale du portail du programme des dveloppeurs

Certier un dveloppeur
An de pouvoir signer une application pour la tester sur un ou plusieurs appareils, un dveloppeur doit au pralable obtenir un certicat approuv par un administrateur du programme des dveloppeurs. Ces certicats doivent tre renouvels tous les ans.

Crer une demande de certicat


Le dveloppeur commence par crer une demande de certicat. 1 Ouvrez lapplication Trousseau dAccs ; elle est situe dans le dossier Utilitaires des Applications. Il faut vrier que le paramtrage des certicats est adquat. Slectionnez la commande Prfrences du menu Trousseau daccs et vriez le paramtrage des certicats ; les protocoles OCSP et CRL doivent tre dsactivs.

Figure 14.7 : Vrication du paramtrage des certicats

14.3. Processus de diffusion

417

2 Fermez la fentre des prfrences puis slectionnez la commande Demander un certicat une autorit de certication du sousmenu Assistant de certication du menu Trousseau daccs. 3 Saisissez votre nom et votre adresse de courriel de la mme faon que lors de votre enregistrement sur le site des dveloppeurs. Slectionnez les options Enregistre sur le disque et Me laisser indiquer les donnes sur la bi-cl puis cliquez sur le bouton Continuer.

Figure 14.8 : Cration dune demande de certicat

4 Indiquez lemplacement et le nom du chier que vous souhaitez crer. Vous pouvez laisser le nom par dfaut CerticateSigningRequest.certSigningRequest. Indiquez les paramtres de la bi-cl : 2048 bits et RSA.

Figure 14.9 : Paramtrage de la bi-cl

Un couple de cl prive-publique est alors cr dans votre trousseau de session et le chier de demande de certicat est cr. Il faut

418

14. Annexe

maintenant envoyer cette demande sur le portail du programme des dveloppeurs.

Conserver cette demande de certificat


Conservez cette demande de certicat, vous pourrez la rutiliser pour gnrer un certicat de diffusion.

Obtenir le certicat
1 Slectionnez la fonction Certicates sur le portail du programme des dveloppeurs. Longlet Development vous permet de transfrer le chier contenant la demande de certicat (CerticateSigningRequest.certSigningRequest). Un administrateur doit approuver la demande de certicat. Une fois cette validation effectue, vous pouvez tlcharger le certicat depuis le mme onglet du portail.

Auto-approbation
Mme lorsque lquipe de dveloppement est compose dune seule personne, cette dernire doit approuver sa propre demande de certicat.

Figure 14.10 : Tlchargement des certicats

2 Tlchargez galement le certicat intermdiaire WWDR.

Installer les certicats


Vous avez ainsi rcupr :
j j

votre certicat personnel, dans un chier developer_identity.cer ; un certicat intermdiaire AppleWWDRCA.cer.

Double-cliquez sur chacun de ces chiers pour les installer dans le Trousseau daccs de votre session. Les certicats sont maintenant installs et prts tre utiliss sous XCode.

14.3. Processus de diffusion

419

Tester son application sur un appareil


Identier les appareils
Lidentiant dun appareil peut tre obtenu, lorsque lappareil est connect un Mac, sous XCode ou sous iTunes. Sous iTunes, il suffit de cliquer sur le numro de srie de lappareil, dans la page Rsum, pour faire apparatre son identiant (UDID) ; cest une suite de 40 caractres alphanumriques. Lorsquil est affich sous iTunes, on peut copier lidentiant dans le Presse-papiers (X+[C]). La gestion des appareils de test sous XCode est ralise dans la fentre Organizer. 1 Slectionnez la commande Organizer du menu Windows ou tapez le raccourci clavier [Ctrl]+X+[O]. 2 Slectionnez lappareil dans le bandeau gauche et longlet Summary pour en afficher les paramtres, dont lidentiant (identier).

Figure 14.11 : Identiant de lappareil sous XCode

Enregistrer les appareils


Les administrateurs du compte du programme peuvent enregistrer des appareils de test sur le portail. Enregistrez votre appareil sur le portail du programme des dveloppeurs, dans la fonction Devices. Procdez de la mme faon pour enregistrer tous les appareils sur lesquels vous souhaitez tester vos applications en cours de dveloppement.

Figure 14.12 : Appareils enregistrs sur le portail

420

14. Annexe

Vous pouvez enregistrer jusqu 100 appareils par an. Apple vous propose une fois par an dapurer cette liste des appareils que vous nutilisez plus.

Identier les applications


Un identiant dapplication est compos dun prxe de 10 caractres fournis par Apple (Bundle Seed ID) et dun identiant de paquetage (Bundle ID) transmis par un administrateur. Il est recommand dutiliser une notation de domaine inverse pour identier un paquetage, par exemple com.jpiconseil.convertpro. Pour crer un identiant dapplication, connectez-vous sur le portail du programme et slectionnez la fonction App ID. Cliquez sur le bouton Create Add ID et saisissez :
j

un nom qui vous permettra de reprer lidentiant pour en faciliter la gestion ; un identiant de paquetage ; cest cet identiant quil faudra insrer dans les informations de lapplication sous XCode.

Cliquez sur le bouton Submit. Lidentiant dapplication est gnr.

Figure 14.13 : Identiants dapplications sur le portail

Identifiant du paquetage
Lidentiant du paquetage devra tre saisi dans le chier Info.plist de lapplication sous XCode.

Partage de lidentifiant dapplication


Les applications qui doivent partager les mmes mots de passe, pour accder des sites web par exemple, doivent avoir le mme identiant dapplication. Pour ce faire, il faut saisir un identiant de paquetage avec un caractre joker "*", par exemple com.jpiconseil.*.

14.3. Processus de diffusion

421

Gnrer un prol dautorisation


Un prol dautorisation (provisioning prole) est un chier qui doit tre install sur un appareil an de pouvoir y excuter des applications. Il contient :
j j j

un identiant dapplication ; un ou plusieurs certicats de dveloppement ; un ou plusieurs identiants dappareil.

Les prols dautorisation pour le test sont gnrs par un administrateur. Ils seront ensuite tlchargs par les dveloppeurs pour tre utiliss. Pour crer un prol dautorisation, connectez-vous sur le portail du programme des dveloppeurs, slectionnez la fonction Provisioning dans le bandeau gauche puis longlet Development. Cliquez sur le bouton New Prole, saisissez les informations demandes puis cliquez sur Submit.

Figure 14.14 : Cration dun nouveau prol dautorisation

Ces prols sont valables 3 mois. Ils peuvent tre dits et renouvels par un administrateur.

Installer un prol dautorisation


Pour pouvoir tester une application sur un appareil, ce dernier doit tre connect sur le poste du dveloppeur qui doit comporter :

422

14. Annexe

j j

le certicat du dveloppeur dans le Trousseau dAccs ; le prol dautorisation adquat dans XCode.

Procdez ainsi : 1 Pour tlcharger un prol dautorisation, connectez-vous sur le portail du programme des dveloppeurs, slectionnez la fonction Provisioning dans le bandeau gauche puis longlet Development.

Figure 14.15 : Liste des prols disponibles

2 Cliquez sur le bouton Download du prol que vous souhaitez obtenir. Une fois le tlchargement termin, connectez lappareil sur lequel vous souhaitez transfrer le prol, ouvrez la fentre Organizer sous XCode ([Ctrl]+X+[O]) puis faites glisser le chier tlcharg (un chier dextension .mobileprovision) dans la zone Provisioning correspondant lappareil.

Figure 14.16 : Installation dun prol dautorisation sous XCode

14.3. Processus de diffusion

423

Utilisation des profils tlchargs


Bien que tous les membres dune quipe puissent tlcharger un prol dautorisation, seuls les dveloppeurs dont le certicat est inclus dans le prol pourront utiliser celui-ci.

Construire lapplication pour lappareil


Une fois que vous disposez dun certicat et dun prol install sous XCode, vous pouvez construire votre application pour lappareil, ly installer et la tester.

Compiler pour un appareil rel


Ouvrez le projet de votre application sous XCode et dans la barre doutils de la fentre principale, slectionnez un iPhone Device dans le menu droulant Active SDK.

Figure 14.17 : Slection du SDK pour un appareil rel

Signer lapplication
1 Dans la liste gauche de la fentre principale, ouvrez le groupe Targets et slectionnez la cible correspondant votre application. Cliquez du bouton droit et slectionnez la commande Get Info du menu contextuel (voir Figure 14.18). 2 Dans la fentre dinformations qui souvre, saisissez sign dans le champ de recherche an de limiter la liste des informations affiches. Ouvrez la rubrique Code Signing Identity pour dnir la valeur du paramtre Any iPhone OS Device : iPhone Developer (voir Figure 14.19).

424

14. Annexe

Figure 14.18 : Ouverture de la fentre des informations de lapplication

Figure 14.19 : Signature du code pour le test en dveloppement

14.3. Processus de diffusion

425

Identier lapplication
Sous XCode, slectionnez le groupe Ressources puis le chier Info.plist de lapplication. Modiez le paramtre Bundle Identier pour lui donner la valeur de lidentiant de paquetage que vous avez dni lors de lidentication de lapplication sur le portail du programme des dveloppeurs.

Figure 14.20 : Identication du paquetage sous XCode

Tester lapplication sur lappareil


Vous pouvez maintenant connecter votre appareil et lancer lexcution depuis XCode (X+[R]). Lapplication est charge sur lappareil et excute sur celui-ci.

Diffusion limite de son application


Une diffusion limite permet un usage priv de votre application ou un bta-test avant une diffusion publique.

Crer un certicat de diffusion


Seul lagent du compte du programme des dveloppeurs peut diffuser une application. Il doit pour cela commencer par crer son certicat de diffusion. Le processus est identique celui utilis pour crer un certicat de dveloppeur.
426
14. Annexe

Ce certicat doit tre renouvel tous les ans.

Crer une demande de certicat


La demande de certicat est cre exactement de la mme faon que pour un dveloppeur.

Utiliser la mme demande de certificat


La demande de certicat que vous avez gnre pour le certicat de dveloppeur est utilisable pour obtenir un certicat de diffusion.

Obtenir le certicat
1 Slectionnez la fonction Certicates sur le portail du programme des dveloppeurs. Longlet Distribution vous permet de transfrer le chier contenant la demande de certicat (CerticateSigningRequest.certSigningRequest). Cliquez sur le bouton Request Certicate.

Figure 14.21 : Accs la demande de certicat

2 Envoyez votre demande de certicat sur le site puis approuvez-la ; votre certicat de diffusion est prt tre tlcharg.

Figure 14.22 : Tlchargement du certicat

14.3. Processus de diffusion

427

Installer le certicat
De la mme faon que pour le certicat de dveloppeur, doublecliquez sur le chier distribution_identity.cer que vous venez de tlcharger pour linstaller dans le Trousseau daccs de votre session. Votre certicat de diffusion est install et prt tre utilis sous XCode.

Crer et installer un prol de diffusion limite


Vous avez dj gnr un prol dautorisation pour le dveloppement. De la mme faon, nous allons crer un prol dautorisation pour la diffusion limite (ad hoc distribution provisioning prole). Seul lagent du compte peut crer et utiliser un prol de diffusion limite. 1 Connectez-vous sur le portail du programme des dveloppeurs, slectionnez la fonction Provisioning dans le bandeau gauche puis longlet Distribution. Cliquez sur le bouton New Prole, saisissez les informations demandes en particulier choisissez ad hoc pour une diffusion limite , puis cliquez sur Submit.

Figure 14.23 : Cration dun prol de diffusion limite

Ces prols sont valables 1 an. Ils peuvent tre dits et renouvels par lagent du compte. 2 Revenez la liste des prols de diffusion et cliquez sur le bouton Download du prol que vous souhaitez obtenir.

428

14. Annexe

3 Ouvrez la fentre Organizer sous XCode ([Ctrl]+X+[O]) puis faites glisser le chier tlcharg (Convert_Pro_Ad_Hoc.mobileprovision) dans la zone Provisioning correspondant lappareil connect.

Figure 14.24 : Installation dun prol dautorisation sous XCode

4 Conservez le chier contenant le prol de diffusion ; les utilisateurs en auront besoin pour installer votre application sur leurs appareils.

Construire lapplication pour la diffusion


Interdire le contrle externe
Les applications en dveloppement peuvent tre lances et examines depuis lordinateur de dveloppement sur lequel lappareil est connect en USB. Cette possibilit est interdite pour les applications diffuses, il faut donc congurer lapplication cet effet. 1 Sous XCod, crez un nouveau chier (X+[N]). Dans la rubrique Code Signing de liPhone OS, choisissez le type Entitlements puis cliquez sur le bouton Next (voir Figure 14.25). 2 Donnez un nom ce chier, par exemple Entitlement.plist, puis cliquez sur le bouton Finish.

14.3. Processus de diffusion

429

Figure 14.25 : Cration dun chier Entitlements

Le fichier doit tre la racine


Vriez que le chier est bien cr la racine du projet, quil nappartient aucun groupe.

3 Slectionnez ce chier sous XCode et dcochez la case get-taskallow.

Figure 14.26 : Interdiction du contrle externe

Construire lapplication
La construction pour la diffusion ncessite un paramtrage spcique. Nous allons donc crer une conguration sous XCode. 1 Cliquez du bouton droit sur la cible de lapplication et slectionnez la commande Get Info du menu contextuel qui saffiche.

430

14. Annexe

Figure 14.27 : Afficher les informations de la cible

2 Slectionnez longlet Build dans la fentre dinformation et ouvrez le menu Conguration. Slectionnez la commande Edit Congurations .

Figure 14.28 : diter les congurations

3 Slectionnez la conguration Release dans la liste puis cliquez sur le bouton Duplicate. Changez le nom de la conguration cre : Distribution.

14.3. Processus de diffusion

431

Figure 14.29 : Cration dune conguration Distribution

4 Refermez la fentre pour revenir aux informations de la cible. Slectionnez la conguration Distribution puis saisissez sign dans le champ de recherche. Nous allons congurer la signature de lapplication pour la distribution. 5 Modiez le paramtre Code Signing Entitlements, saisissez le nom du chier que vous avez cr : Entitlement.plist. 6 Modiez le sous-paramtre Any iPhone OS Device du paramtre Code Signing Identity pour lui donner la valeur iPhone Distribution.

Figure 14.30 : Paramtrage de la conguration Distribution

432

14. Annexe

7 Fermez la fentre dinformation de la cible. Sous XCode, slectionnez la conguration Distribution laide de la commande Set Active Build Conguration du menu Project. 8 Effacez les constructions prcdentes avec la commande Clean ([Maj]+X+[K]) et construisez lapplication (X+[B]). Lapplication est prte tre distribue.

Distribuer son application


Lapplication termine se trouve dans le dossier du projet sous XCode, dans le sous-dossier build.

Figure 14.31 : Localisation de lapplication termine

Transmettez lapplication ainsi que le prol de diffusion aux utilisateurs. Ils devront faire glisser ces deux chiers dans lapplication iTunes puis synchroniser leur appareil.

Compressez lapplication
Il faut compresser lapplication (format ZIP) pour la transmettre par courriel. Le type de chier .app tant un dossier (Bundle), il est dconseill de le placer directement en pice jointe.

Lapplication est alors prte tre utilise.

14.3. Processus de diffusion

433

Diffuser son application sur lAppStore


Apple met la disposition des dveloppeurs le site iTunes Connect (https://itunesconnect.apple.com) pour grer la diffusion des applications sur lApp Store. Louverture dun compte sur le programme standard des dveloppeurs provoque automatiquement la cration dun compte sur liTunes Connect avec le mme mot de passe. Ce compte est immdiatement disponible pour la diffusion dapplications gratuites, la diffusion dapplications payantes sera possible aprs avoir saisi les informations bancaires et scales.

Figure 14.32 : Site web iTunes Connect

Engagement iTunes Connect


Lors de votre premire connexion sur le site de liTunes Store, il vous est demand dapprouver les conditions dutilisation. En acceptant ces conditions, vous vous engagez :
j

fournir des informations juridiques, bancaires et scales exactes et prcises concernant votre organisation, ou votre situation personnelle, et mettre jour ces informations ;

434

14. Annexe

ne pas divulguer votre identiant et votre mot de passe (vous avez la possibilit dajouter des utilisateurs sur le mme compte, avec leur propre identiant) ; accepter les conditions de vente sur lApp Store.

En outre, Apple ne garantit pas le bon fonctionnement de liTunes Connect.

Prol de diffusion
Le processus pour crer un prol de diffusion sur lApp Store est exactement le mme que pour un prol de diffusion limite. La seule diffrence est quil faut slectionner App Store la place de Ad Hoc pour le paramtre Distribution Method du prol. La construction de lapplication est ralise de la mme faon quel que soit le type de diffusion.

Soumission dune application


Considrations lgales
Vous devez donner un nom votre application an de la diffuser ; veillez ne pas utiliser le nom dune marque dont vous ne dtiendriez pas les droits. Concernant lutilisation des logos et des marques dposes par Apple, vous pouvez consulter la page http://www.apple.com/legal/trademark /guidelinesfor3rdparties.html. En rsum, vous navez le droit dutiliser aucun nom de marque dpos par Apple ni aucun driv, lexception notable du terme Mac qui peut tre utilis lorsquil est combin (MacWorld, MacProject, etc.) mais pas seul. La liste des marques dposes par Apple peut tre consulte sur la page http://www.apple.com/legal/trademark/appletmlist.html.

Prparer la soumission
La soumission dune application sur liTunes Connect nest pas complexe mais assez longue. Il est conseill de prparer tous les lments :
j j j

le nom de lapplication ; une description de lapplication (4 000 caractres au maximum) ; le type dappareil sur lequel lapplication fonctionne : iPhone, iPod touch, iPad ou iPhone/iPad (pour les applications universelles) ; un numro de rfrence (SKU) devant identier sans ambigut chaque version majeure de chacune de vos applications ;
14.3. Processus de diffusion

435

j j j

j j j

la catgorie principale de lapplication (voir le tableau) et ventuellement une catgorie secondaire ; le numro de version ; le copyright, par exemple 2010 JPIConseil ; ladresse du site web o lutilisateur peut trouver des informations complmentaires ; une adresse de courriel ; cette adresse sera utilise par Apple, elle ne sera pas diffuse ; ventuellement le texte de la licence dutilisation de lapplication, par dfaut la licence standard de lApp Store sapplique ; la liste des pays ou zones gographiques sur lesquels on souhaite diffuser lapplication ; la date de disponibilit de lapplication ; le prix de lapplication ; ventuellement, les localisations pour le texte descriptif et la licence dutilisation. Les localisations admises sont langlais, le franais, lallemand, le hollandais, litalien, lespagnol et le japonais ; licne de votre application en grand format ; 512 x 512, 72 dpi, au format JPEG ou TIFF ; la copie de lcran principal de votre application, au format JPEG ou TIFF ; pour iPhone ou iPod Touch, 320 x 460 (sans la barre dtat), ou 320 x 480 (pour les applications plein cran), 480 x 300 ou 480 x 320 ; pour iPad 1 024 x 748, 1 024 x 768, 768 x 1 004 ou 768 x 1 024.

ventuellement des copies dcrans additionnelles :

Tableau 14.2 : Catgories dapplications sur lApp Store Anglais Book Business Education Entertainment Finance Games Healthcare & Fitness Franais Livres numriques conomie et entreprise Enseignement Divertissement Finance Jeux Forme et sant Anglais Navigation News Photography Productivity Reference Social Networking Sports Franais Navigation Actualits Ptotographie Productivit Rfrences Rseaux sociaux Sports

436

14. Annexe

Tableau 14.2 : Catgories dapplications sur lApp Store Anglais Lifestyle Medical Music Franais Style de vie Mdecine Musique Anglais Travel Utilities Weather Franais Voyages Utilitaires Mto

Aprs avoir saisi ces informations, il vous faudra attendre la validation dApple, de quelques jours quelques semaines, avant de voir votre application sur lApp Store.

Autres services
Pour amliorer votre marketing, Apple vous autorise utiliser gratuitement un logo an de signaler la prsence de votre application sur lApp Store, ainsi que les photos officielles dun iPhone et dun iPod touch pour y insrer vos copies dcran. Pour cela, renvoyez laccord de licence sign. Consultez les informations sur le site http://developer.apple.com/iphone/appstore/. Vous pouvez encore renforcer vos liens avec liTunes Store et vous affilier liTunes : http://www.apple.com/uk/itunes/affiliates.

14.3. Processus de diffusion

437

!
#dene................................................ 168 #import ................................................. 53 #include................................................ 54

Badge ......................................... 176, 179


BadgeValue............................................. 176 donglets ................................................. 175 de navigation .......................................... 181 de progression ........................................ 136

A
Abscisses .......................................... 275 Acclromtres................................ 365 Accesseur ..................................... 56, 66 Action ................................................... 57
Dclaration ............................................... 51

Bascule .............................................. 136 Binary data ........................................ 332 Boucle dvnement........................ 109 Bounds ............................................... 277 Bouton................................................ 136
de retour ................................................. 181

Activity Indicator .............................. 137 Administrateur .................................. 412 Agent .................................................. 412 Albums ............................................... 323 Aligner.................................................. 36 Alloc...................................................... 70 Alpha .................................................. 275 Analyseur de geste.......................... 396 Animation........................................... 269 Annotation ......................................... 359 App Store........................................... 434 Application barre donglets......... 176 ApplicationDidFinishLaunching ..... 112 AppStore............................................ 410 Ascenseur ......................................... 137 Assign............................................. 85, 87 Atomique............................................ 345 Attribut........................................ 234-235 Attribute ............................................. 234 Autorelease......................................... 89
Autorelease pool ...................................... 89

Buffers................................................ 293 Build ......................................... 28, 56, 59 Bundle ................................................ 149


Bundle ID ................................................ 421 Bundle Seed ID ....................................... 421

C
CADisplayLink ................................... 297 Cadre .......................................... 150, 276 Calendrier .......................................... 191 Calibration ......................................... 351 Cardinalit ......................................... 234 Carte ................................................... 352 Cell ...................................................... 214 Cellule................................................. 214 Centre des membres ....................... 414 Certicat ............................................ 417 CGPoint .............................................. 277 CGRect ............................................... 277 CGSize ................................................ 277 Champ de Texte ................................ 137 Chiquenaude ..................................... 313 Cible...................................................... 57
cible-action ............................................. 303

Autorotation .............................. 379, 387 Autosizing .......................................... 380 AVAudioPlayer.................................. 273

Classe................................................... 43
nommage .................................................. 52

B
Back Button....................................... 181

Clean................................................... 124 CLHeading ......................................... 351 CLLocation......................................... 348 CLLocationManager ................ 343, 350

Index

439

INDEX

Barre

CLLocationManagerDelegate ....... 344, 347, 350 Codage par valeur de cl ............... 101 Code
completion ................................................ 55 factorisation.............................................. 93 terminaison ............................................... 55

Colors ................................................... 48 Commentaire....................................... 64 Compas magntique ........................ 349 Components ...................................... 199 Composants....................................... 199 Compteur de rfrences................... 84 Connections .................................. 50, 57 Construction pour la diffusion........ 430 Construire ............................................ 59 Conteneurs ........................................ 205 Contexte
Core Data................................................ 240 graphique ................................................ 284

Dnition........................................ 52, 68 Dlgation ......................................... 101 Dlgu.............................................. 200 Dplacement..................................... 274 Dploiement ...................................... 385 Descripteur de tri ............................. 247 Design patterns ................................ 101 Dictionnaire............................... 203, 207 Diffusion
ad hoc ..................................................... 412 application .............................................. 410 limite............................................. 412, 428 publique .................................................. 412

DrawRect........................................... 283 Dures................................................ 192

E
lments ............................................ 176 Encapsulation ..................................... 52 @end .............................................. 64, 68 Entits................................................. 234 Entity................................................... 234 quipe de dveloppement .............. 412 Erreur.................................................. 244 vnement......................................... 303
boucle ............................................... 89, 109

Contrle................................................ 62
de pages ................................................. 137 invers .................................................... 199

Contrleur de navigation ................ 182 Coordonnes..................................... 275 Copy................................................ 85, 87 Core Data................................... 233, 332
contexte .................................................. 240

CoreGraphics .................................... 283 Courriels............................................. 336

Events................................................. 303 EXC_BAD_ACCESS............................ 95 EXC_BAD_INSTRUCTION............... 107

D
DataSource ....................................... 200 Date picker ........................................ 187 Dates .................................................. 191 Dealloc..................................... 72, 84, 91 Debogueur........................................... 96 Debug ................................................... 97 Debugger ............................................. 96 Dclaration.................................... 52, 63
Action........................................................ 51

F
Factorisation du code........................ 93 Fichier
ajouter....................................................... 30 chargement NIB...................................... 110

Default.png .......................................... 36

Files Owner .................................. 50, 58 First responder ................. 133, 304, 309 Float ...................................................... 56 Fonts ..................................................... 48 For in................................................... 205

440

Index

Format
de date.................................................... 194 rgional ................................................... 121

Frame.......................................... 150, 276 Framebuffer ....................................... 293

Invitation ............................................ 416 IPhone Simulator................................ 28 ITunes Connect................................. 434

G
Go-localisation ............................... 343 Gestes ................................................ 306
analyseur de geste ................................. 396

J
JPEG ................................................... 269

K
Key Value Coding ............................. 101 Keyboard.............................................. 49 KVC ..................................... 101, 127, 246

Gestionnaire de go-localisation .. 343 Getter.............................................. 66, 85 Graphique .......................................... 269

H
Hritage ......................................... 51, 60 Hirarchie de vues............................. 62 Home .................................................... 80

L
Label...................................... 26, 136-137 Lancement........................................... 36 Latitude .............................................. 349 Layer................................................... 281 Leaks .................................................... 79 Library ............................................ 26, 35 Lignes ................................................. 199 Limites ................................................ 277 Listes de proprits ......................... 258 Localisation ....................................... 120 Logo ...................................................... 32 Longitude ........................................... 349

I
IBAction................................. 51, 65, 128 IBOutlet ................................................ 46 Id ........................................................... 65 Identiant................................... 413, 420
dapplication ........................................... 421

Image.............................................. 30, 35 Immuables ......................................... 208 Implementation............................. 52, 68 Indexed .............................................. 236 Indicateur dactivit......................... 136 Init.................................................... 70-71 Initialiseur dsign............................. 71 InitWithNibName Inspecteur ......................... 36, 48, 50, 57 Instance ............................................... 43 Instruments ......................................... 79 Interface ........................................ 52, 64 Interface Builder ................................ 26

M
Macro-instruction ............................ 168 MainWindow.xib............................... 109 Manipulateur....................................... 66 MapKit................................................ 352 Marques dposes .......................... 435 Media ................................................... 35 Mmoire............................................... 92
fuite........................................................... 78 rgle.................................................... 88, 90

Message ........................................ 44, 69


441

Index

Mthode............................................... 42
dinstance ................................................. 65 de classe................................................... 65 dclaration ................................................ 65 nommage .................................................. 66

MFMailComposeViewController.... 337 MFMailComposeViewController Delegate............................................. 338 MIME.................................................. 338 MKAnnotation................................... 359 ModalTransitionStyle....................... 151 Mode dition ..................................... 254 Model-View-Controller............ 101, 134 Modle de donnes......................... 234 Modle-Vue-Contrleur .......... 101, 134 Motifs de conception ...................... 101 Multi-threading................................... 86 Mutable.............................................. 208 MVC ............................................ 101, 134

N
Navigateur de Classes .................... 147 Navigation Bar.................................. 181 Navigation Controller....................... 182 NextStep ............................................ 191 NIB........................................................ 25 Nil.......................................................... 70 Nommage
classe ........................................................ 52 mthode .................................................... 66 variable ..................................................... 65

NSEntityDescription......................... 239 NSError .............................................. 244 NSFetchedRequest .......................... 247 NSFetchedResultsController.......... 243 NSFetchedResultsController Delegate............................................. 244 NSFetchedResultsSectionInfo....... 243 NSFetchRequest............................... 243 NSIndexPath ............................. 211, 214 NSManagedObjectContext............. 240 NSManagedObjectModel............... 239 NSMutableArray .............................. 208 NSMutableDictionary...................... 208 NSNull ................................................ 205 NSNumber................................. 127, 261 NSObject.............................................. 60 NSPersistentStore ........................... 240 NSPersistentStoreCoordinator ...... 240 NSScanner ........................................ 117 NSSortDescriptor............................. 247 NSString............................................... 56 NSTimeInterval ................................. 192

O
Objective-C.......................................... 15 Objet ..................................................... 42
comportement........................................... 42 tat............................................................ 42 libration................................................... 72 message.................................................... 69 nul ........................................................... 205 programmation ......................................... 41

Nonatomic...................................... 85-86 Nord.................................................... 349 Notation pointe................................. 70 Notication................................ 263, 377 NSArray ............................................. 205 NSCharacterSet ............................... 104 NSClassFromString.......................... 298 NSData............................................... 333 NSDate............................................... 192 NSDateFormatter ............................. 193 NSDictionary............................. 203, 207
442
Index

Observateur....................................... 264 Onglet ................................................. 175 OpenGL............................................... 291 Oprateur de rfrencement ......... 117 Optional.............................................. 236 Ordonnes ......................................... 275 Orientation......................................... 377 Outlet .................................................... 46
connexion.................................................. 50

Outlets ................................................ 110

P
Page Control...................................... 138 Paquet ................................................ 149 Paysage ............................................. 377 Photos ........................................ 323, 329 Picker ................................................. 187 Picker View ....................................... 196 Pile ...................................................... 183
de navigation .......................................... 183 tat............................................................ 80

Rfrence ............................................ 77
obsolte .................................................... 94

Pincement.......................................... 313 PNG..................................................... 269 Pool dautolibration.......................... 89 Popover ...................................... 389-390 Portail des autorisations................. 414 Porte................................................... 43 Portrait ............................................... 377 Positionnement................................... 36 Premier rpondeur................... 133, 304 PresentModalViewController......... 151 Prix...................................................... 411 Prol dautorisation.......................... 422 Progress View................................... 137 Projet .................................................... 19
crer .......................................................... 20 fentre ...................................................... 23 modles .................................................... 21

Refurb Store ........................................ 11 Rgle dintgrit ............................... 255 Relations .................................... 234, 237 Relationship....................................... 234 Release .................................... 72, 84, 97 Rpondeur ........................................... 60 Requte.............................................. 247 ResignFirstResponder ..................... 132 RespondsToSelector........................ 107 Retain........................................... 84 86 Retain count ........................................ 84 Root View........................................... 181 Round Rect Button........................... 137 Rows................................................... 199

S
Sandbox ............................................... 15 SDK......................................... 12, 59, 409 Secousse ........................................... 304 Segmented Control .......................... 137 SEL ...................................................... 107 Slecteur ........................................... 136 Slection multiple............................... 48 Slectionneur de date..................... 187 @selector........................................... 107 Self........................................................ 72 Setter.............................................. 66, 85 Shake.................................................. 304 Signature du code............................ 411 Simulateur ........................................... 28 Slider .................................................. 137 Son...................................................... 273 Source de donnes.......................... 200 Splitview .................................... 388, 392 SQLite ................................................. 233 Stack..................................................... 80 Super .................................................... 72 Superclasse ........................................ 64

Property ............................................... 69 @property (attributs) ......................... 85 Property list ....................................... 258 Proprit .............................................. 69
libration................................................... 91 notation pointe ....................................... 70

Protocole ........................................... 107 Provisioning prole .......................... 422

R
Readonly .............................................. 85 Readwrite ............................................ 85 Recadrer ............................................ 336

Index

443

Switch ................................................ 137 @synthesize ............................ 56, 69, 85

T
Tab Bar Application ......................... 176 Tab Bar Controller ............................ 176 TabBarItem ........................................ 179 Tableau............................................... 205 TableView .......................................... 208 Target ................................................... 57 Temporisateur ................................... 279 Terminaison de Code ......................... 55 Test ..................................................... 411 Tester (Interface)................................ 51 Text Field...................................... 47, 138 Texte (champ) ................................... 137 Transient ............................................ 236 Tri......................................................... 247

U
UDID ................................................... 420 UIAcceleration.................................. 366 UIAccelerationValue........................ 367 UIAcceleromer ................................. 366 UIAccelerometerDelegate.............. 366 UIActionSheet................................... 172 UIActionSheetDelegate .................. 174 UIActivityIndicatorView .................. 137 UIAlertView........................ 170-171, 174 UIAlertViewDelegate....................... 174 UIApplication ............................ 109, 303 UIApplicationDelegate .................... 109 UIApplicationMain ........................... 109 UIButton............................................. 137 UIControl...................................... 62, 303 UIDatePicker..................................... 190 UIDevice .................................... 298, 377 UIDeviceOrientation ........................ 377 UIEvent............................................... 306

UIGestureRecognizer ...................... 396 UIImage.............................................. 272 UIImagePickerController ........ 323, 328 UIImagePickerController Delegate............................................. 330 UIImageView............................. 270, 272 UIKit ...................................................... 53 UILabel ............................................... 137 UILongPressGestureRecognizer ... 397 UINavigationController.................... 182 UIPageControl................................... 138 UIPanGestureRecognizer ............... 397 UIPickerView ............................ 196, 199 UIPickerViewDataSource............... 197 UIPickerViewDelegate .................... 197 UIPinchGestureRecognizer ............ 397 UIPopoverController ........................ 390 UIPopoverControllerDelegate........ 392 UIProgressView................................ 137 UIResponder ....................... 60, 132, 303 UIRotationGestureRecognizer ....... 397 UISegmentedControl ....................... 137 UISlider .............................................. 137 UISplitViewController ...................... 393 UISplitViewControllerDelegate...... 393 UISwipeGestureRecognizer ........... 397 UISwitch ............................................ 137 UITabBar ............................................ 175 UITabBarController .................. 177, 180 UITabBarControllerDelegate.......... 180 UITabBarItem .................................... 176 UITableView ...................................... 210 UITableViewCell ....................... 211, 214 UITableViewController..................... 211 UITableViewDataSource................. 211 UITableViewDelegate ...................... 211 UITapGestureRecognizer................ 397 UITextField ................. 45-46, 60, 62, 138 UITextFieldDelegate......... 103, 107, 156 UITouch .............................................. 305 UIView.......................................... 61, 282

444

Index

UIViewController ................................ 60 UIWindow............................................ 62 Unicode.............................................. 194 Universelle......................................... 387

Vue ........................................................ 61
contextuelle ..................................... 389-390 en table................................................... 208 modale ............................................ 152, 389 racine ...................................................... 181 scinde............................................ 388, 392

V
Variable
nommage .................................................. 65 dinstance ........................................... 42, 64

X
XCode ................................................... 19 XML..................................................... 258

Versions Bta.................................... 410 Vido........................................... 329, 335 View-based Application........ 45, 54, 63 ViewController .................................... 45 ViewDidLoad ............................. 118, 163 Void ....................................................... 65

Z
Zombi.................................................... 77 Zoomer ............................................... 336

Index

445

Compos en France par Jouve 11, bd de Sbastopol - 75001 Paris

You might also like