Professional Documents
Culture Documents
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.
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.
Met laccent sur un point important, souvent dordre technique quil ne faut ngliger aucun prix.
Chapitre 1
1.1.
Premiers pas
17
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.
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.
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
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.
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
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.
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).
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.
Le logiciel
Lenvironnement de dveloppement est disponible gratuitement sur le site des dveloppeurs dApple http://developer.apple.com. Dans la suite
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.
12
Introduction
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.
tester ou diffuser en mode Priv vos applications sur des appareils rels (jusqu 100) ;
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.
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
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.
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-
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.
HelloWorld graphique ;
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.
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.
19
Si cest la premire fois que vous lancez XCode, la fentre daccueil apparat lcran. Vous pouvez fermer cette fentre.
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
LAssistant New Project saffiche, vous permettant de choisir le type de projet que vous souhaitez crer.
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.
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.
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.
Grer le projet
La fentre de projet permet de grer tous les lments dun projet.
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 ;
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.
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 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.
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.
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
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.
Lapplication HelloWorld est construite par XCode et lance dans le simulateur diPhone
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
Vous pouvez aussi lancer votre application sur le simulateur diPad en slectionnant le SDK iPhone Simulator 3.2 sous XCode.
En explorant le simulateur, vous verrez que le logo permettant de lancer notre application HelloWorld est un carr blanc. Nous amliorerons cela immdiatement.
29
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.
30
1. Premiers pas
Un panneau saffiche pour que vous puissiez prciser la faon dont vous souhaitez ajouter le 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).
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.
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.
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.
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.
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.
34
1. Premiers pas
Reportez-vous la section prcdente si vous ne vous souvenez plus comment on ajoute un chier au projet.
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.
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.
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 :
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.
Vous devrez dabord patienter car il faut que vous compreniez ce quest la 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).
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.
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.
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.
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.
Lobjet charg deffectuer les conversions sera une instance de la classe Convertisseur1ViewController ; nous verrons pourquoi dans un instant.
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.
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
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
Rappelez-vous ; pour modier les attributs dun objet, on utilise linspecteur aprs avoir slectionn lobjet que lon veut modier.
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
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.
49
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.
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.
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.
Action
Une action est une mthode dinstance dont la vocation est dtre excute lorsquun vnement survient. Elle est congurable laide dInterface Builder.
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.
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.
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.
#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>.
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".
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.
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
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.
56
2. Interactions simples
Vriez que votre code source ne contient pas derreurs et corrigez ces dernires ventuellement avant de passer ltape suivante.
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 ;
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.
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.
4 Slectionnez nouveau Files Owner pour visualiser ses connexions dans linspecteur.
58
2. Interactions simples
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.
Nous nous rendons compte de tous les petits dfauts de notre application. Il faudra lamliorer avant de rellement lutiliser :
j
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.
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.
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.
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.
62
2. Interactions simples
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.
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 :
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.
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.
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.
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.
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.
65
Pour comprendre la dclaration des mthodes ayant des paramtres, nous allons dtailler un exemple :
- (void)getCharacters:(unichar *)buffer range:(NSRange)aRange ;
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.
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
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
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
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;
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
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];
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];
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;
71
Cest loccasion de faire la connaissance de deux mots-cls importants en Objective-C : super et self.
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]; }
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.
2.5. Check-list
73
j j j
envoi de message ; mots-cls super et self et nil ; mthodes impliques dans le cycle de vie des objets :
+alloc ;
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.
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.
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.
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.
79
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).
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.
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.
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.
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.
83
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.
84
3. Gestion de la mmoire
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; }
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)
readonly
Gestion de la mmoire Le com- assign pilateur met un avertissement si lun de ces attributs nest pas utilis
retain
copy
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.
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.
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.
87
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.
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.
89
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
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
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.
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.
91
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]; }
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
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.
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
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.
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.
97
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.
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.
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
101
Editing: (UITextField *)textField pour notier au dlgu que le champ de texte vient dentrer en mode dition.
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.
Cration du dlgu
1 Ouvrez le chier Convertisseur1ViewController.xib sous Interface Builder et connectez loutlet delegate du champ de texte lobjet Files Owner.
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
103
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.
104
4. Motifs fondamentaux
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.
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
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
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 ?
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.
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
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.
MainWindow.nib
Le chier MainWindow.xib est donc charg au lancement de lapplication. Jetons un coup dil dans ce chier laide dInterface Builder.
109
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.
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
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;
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.
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.
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.
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.
114
4. Motifs fondamentaux
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
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).
115
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.
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; }
119
Localiser lapplication
Localiser les montants
Vous avez remarqu deux des nouvelles mthodes que nous avons utilises :
j j
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).
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.
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.
2 Dans la fentre dinformations qui saffiche, cliquez sur le bouton Make File Localizable.
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
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.
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.
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.
125
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; }
126
4. Motifs fondamentaux
Accs par cl
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.
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
3 Enregistrez les chiers modis sous XCode. Vous pouvez galement reconstruire lapplication pour vrier que le code saisi est correct.
128
4. Motifs fondamentaux
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.
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.
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.
130
4. Motifs fondamentaux
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
131
La mthode resignFirstResponder est dnie dans la classe UIResponder. Cette classe gre la 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.
lapplication.
j
cation.
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.
viter que les champs soient effacs en dbut de saisie ; effacer les deux champs lorsque la saisie dbute dans lun des deux.
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
Risque de plantage
Il ne faut pas modier un champ de texte par programmation pendant son dition par lutilisateur.
4.4. Challenges
135
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 -
Segmented Control
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
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/).
Slectionnez iPhone Dev Center. Saisissez votre identiant et votre mot de passe pour accder aux ressources de dveloppement iPhone ; documentation, exemples, vidos, etc.
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
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.
145
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.
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.
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.
147
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.
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.
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.
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.
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.
Testez galement les diffrents types de boutons proposs dans linspecteur des attributs (X+1) sous Interface Builder.
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.
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
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.
153
et
fermez
le
chier
155
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.
156
5. Applications multivues
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.
157
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.
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.
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
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.
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.
161
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
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]; }
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; }
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
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.
165
2 Modiez Finish: :
galement
la
mthode
flipsideViewControllerDid
166
5. Applications multivues
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.
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.
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.
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.
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.
169
[self.delegate flipsideViewControllerDidFinish:self]; } }
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.
@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.
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.
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.
(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.
173
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
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.
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.
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.
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.
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.
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
179
(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
181
une barre de navigation ; nous naurons gnralement pas nous en occuper ; une contrleur de vue racine (UIViewController) qui contient un lment de navigation.
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.
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 ;
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.
Slectionneur de date
Nous allons commencer par une mise en pratique du cas le plus simple : le slectionneur de date (date picker).
187
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.
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.
La classe UIDatePicker
Testez lapplication Picker1 en essayant plusieurs congurations de paramtres sous Interface Builder.
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
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.
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.
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
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.
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
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
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.
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];
195
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.
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
196
6. Contrles complexes
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).
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
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).
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.
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) 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.
Source de donnes
Un slectionneur standard ncessite deux dlgus :
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
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
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; }
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.
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.
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.
Interroger un tableau
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.
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.
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.
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
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.
209
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 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.
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.
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.
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]; }
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]; }
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.
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
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.
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.
215
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.
217
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]; }
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.
219
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; }
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
Ajouter un lment
Classe LendObject
Nous avons besoin dune classe pour reprsenter un objet prt et ses proprits :
j j j
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
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
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
223
Le retour vers lcran prcdent sera pris en charge par le contrleur de navigation ; nous navons pas besoin de nous en occuper ici.
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
un bouton pour permettre lutilisateur de lactionner ; une action connecte sur ce bouton pour activer linterface utilisateur de saisie.
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 ;
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.
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
226
6. Contrles complexes
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.
227
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
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
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
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.
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.
233
Les attributs sont de type scalaire : boolen ; numrique (entier, dcimal ou ottant) ; date ; chane de caractres.
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.
234
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.
235
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.
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
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 ;
237
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.
238
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.
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
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 :
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"];
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
242
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.
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.
243
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:.
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.
244
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
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.
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.
(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
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.
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.
[fetchRequest setFetchBatchSize:20]; NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"categoryName" ascending:YES]; NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil]; [fetchRequest setSortDescriptors:sortDescriptors];
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
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).
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";
250
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.
251
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
[super viewWillDisappear:animated]; }
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.
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.
254
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
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.
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 :
255
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]; } } }
256
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.
257
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
<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>
+ (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
259
Tableau 7.5 : Types de donnes autoriss dans une liste de proprits Type Nombre entier Nombre rel Boolen lment XML Classe Objective-C
Mise en pratique
Nous allons reprendre notre application Convertisseur2 pour la doter de la persistance des donnes. Le principe sera le suivant :
j
tons persistantes.
j
Le chier de donnes est lu au dmarrage de lapplication puis crit lorsque lapplication va quitter.
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
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.
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
Identication du chier
Nous allons nous inspirer de la technique utilise pour identier et grer lunit de stockage Core Data.
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.
262
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
UITableView
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:)
263
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;
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
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.
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.
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.
269
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
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.
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.
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.
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
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
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
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.
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.
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.
275
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.
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.
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.
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).
Vous trouverez la liste exhaustive de ces fonctions dans la documentation CGGeometry Reference.
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]; }
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.
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.
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.
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.
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 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:.
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();
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.
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.
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.
285
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
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.
287
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
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
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)
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
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.
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.
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.
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.
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
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.
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).
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.
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.
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.
295
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
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 ;
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 =
297
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)
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
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
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
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.
Si lvnement est une action sur lcran, le rpondeur est la vue situe sous le doigt de lutilisateur.
303
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
Les vnements concernant les touches sont plus complexes ; chaque touche lmentaire peut tre :
j
304
j j
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.
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.
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.
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
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.
(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
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
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
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
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
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.
311
touchesEnded:withEvent: sil sagit de lvnement qui clt le geste, et dans la mthode touchesCancelled:withEvent: lorsque le geste est interompu.
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
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.
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.
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
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
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
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;
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]; } }
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.
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
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.
319
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
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.
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 :
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
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
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 ;
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.
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.
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
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;
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
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
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,copy) Tableau contenant les mdias dont NSArray *mediaTypes laccs est autoris. kUTTypeImage par dfaut
328
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)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.
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
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.
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
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.
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.
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.
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.
Challenge
Si vous disposez dun iPhone 3GS, vous pouvez modier lapplication pour conserver une capture vido plutt quune photo.
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.
une rfrence vers une instance NSError contenant la description de lerreur ventuelle ; la rfrence vers les informations complmentaires.
une rfrence vers une instance NSError contenant la description de lerreur ventuelle ; la rfrence vers les informations complmentaires.
10.3. Enregistrer ses photos
335
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]; }
336
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) 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
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.
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
338
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
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
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.
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.
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];
@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.
(void) startUpdating Location (void) stopUpdating Location (void) startUpdating Heading (void) stopUpdating Heading (void) dismissHeading CalibrationDisplay
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.
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
double struct { CLLocation Degrees latitude; CLLocation Degrees longitude;} double double double double
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.
(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
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.
349
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,
@property(readonly, nonatomic) CLLocation Direction headingAccuracy @property(readonly, nonatomic) NSDate *timestamp (NSString *) description
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.
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.
353
Tester lapplication
Construisez lapplication sous XCode et testez-la (X+[R]).
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.
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.
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]; }
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.
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
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.
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.
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
#import "Annotation.h"
3 Construisez lapplication pour la tester. Si vous touchez le marqueur dni en mme temps que la zone, le texte saffiche.
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.
Lannexe dcrit le mode opratoire suivre pour tester vos applications sur un appareil rel.
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.
@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.
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]; }
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.
Nous doterons notre vue VerticalView dune proprit vertLine de type GCSize qui contiendra les abscisses et ordonnes de lacclration.
369
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.
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]; }
371
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.
372
12. Acclromtres
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"; }
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
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.
375
376
12. Acclromtres
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];
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.
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
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.
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
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.
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
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
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.
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.
385
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.
386
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.
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.
387
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.
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
linterface utilisateur, prsenter les informations dtailles ou les formulaires de saisie dans une vue contextuelle (popover).
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.
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.
le
contrleur
de
vue
contextuel,
instance
de
la
classe
tuelle ;
j
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
Limitation de la taille
La largeur du contenu dune vue contextuelle doit tre comprise entre 320 et 600 pixels. Sa hauteur est libre.
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
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.
391
On peut galement refermer la vue contextuelle en transmettant le message dismissPopoverAnimated: son contrleur.
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.
392
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.
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.
394
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.
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.
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
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 :
397
j j
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).
UITapGesture 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
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)
CGFloat rotation CGFloat velocity CFTimeInterval minimumPress Duration NSInteger number OfTouches Required NSUInteger number OfTaps Required CGFloat allowable Movement
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.
399
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.
400
@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
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 :
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
[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.
403
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
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.
de tlcharger le SDK ; daccder la documentation Apple ; de tester ses applications avec le simulateur diPhone.
409
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
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 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.
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.
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 ;
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.
412
14. Annexe
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.
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.
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
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.
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.
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.
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.
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.
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.
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
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.
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.
419
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.
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.
Identifiant du paquetage
Lidentiant du paquetage devra tre saisi dans le chier Info.plist de lapplication sous XCode.
421
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.
Ces prols sont valables 3 mois. Ils peuvent tre dits et renouvels par un administrateur.
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.
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.
423
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
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.
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.
2 Envoyez votre demande de certicat sur le site puis approuvez-la ; votre certicat de diffusion est prt tre tlcharg.
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.
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.
4 Conservez le chier contenant le prol de diffusion ; les utilisateurs en auront besoin pour installer votre application sur leurs appareils.
429
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
2 Slectionnez longlet Build dans la fentre dinformation et ouvrez le menu Conguration. Slectionnez la commande Edit Congurations .
3 Slectionnez la conguration Release dans la liste puis cliquez sur le bouton Duplicate. Changez le nom de la conguration cre : Distribution.
431
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.
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.
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.
433
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.
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.
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.
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.
437
!
#dene................................................ 168 #import ................................................. 53 #include................................................ 54
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
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
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
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
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
G
Go-localisation ............................... 343 Gestes ................................................ 306
analyseur de geste ................................. 396
J
JPEG ................................................... 269
K
Key Value Coding ............................. 101 Keyboard.............................................. 49 KVC ..................................... 101, 127, 246
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
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
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
R
Readonly .............................................. 85 Readwrite ............................................ 85 Recadrer ............................................ 336
Index
443
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
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