{"id":1660,"date":"2014-09-13T09:51:24","date_gmt":"2014-09-13T13:51:24","guid":{"rendered":"http:\/\/tim.cstj.qc.ca\/cours\/xcode\/wp\/?page_id=1660"},"modified":"2014-09-13T09:51:24","modified_gmt":"2014-09-13T13:51:24","slug":"projet-posttim-version-swift","status":"publish","type":"page","link":"https:\/\/ve2cuy.com\/xcode\/projet-posttim-version-swift\/","title":{"rendered":"Projet: Post&#039;TIM &#8211; version Swift"},"content":{"rendered":"<h1>Passage de donn\u00e9es, par l&rsquo;utilisation d&rsquo;un\u00a0protocole<\/h1>\n<p>&nbsp;<\/p>\n<h2>Contenu<\/h2>\n<p><img loading=\"lazy\" decoding=\"async\" class=\" wp-image-625 alignleft\" src=\"\/xcode\/wp-content\/uploads\/2014\/09\/post-TIM-entete.png\" alt=\"Post'TIM\" width=\"260\" height=\"470\" \/><\/p>\n<ul>\n<li>Programmer un protocole pour le retour de donn\u00e9es vers une sc\u00e8ne ayant initi\u00e9 un segue.<\/li>\n<li>Documenter correctement les ent\u00eates de classes, les propri\u00e9t\u00e9s et les m\u00e9thodes (documentation en ligne)<\/li>\n<li>Utiliser le dossier &lsquo;Document&rsquo; pour enregistrer les donn\u00e9es d&rsquo;une application<\/li>\n<li>Enregistrer un NSArray dans un fichier de propri\u00e9t\u00e9s (.plist).<\/li>\n<li>Utiliser un formateur de date pour afficher un NSDate en heure locale.<\/li>\n<li>Programmer plusieurs destinations dans la m\u00e9thode &lsquo;prepareForSegue&rsquo;<\/li>\n<\/ul>\n<p><strong>Pr\u00e9-requis:<\/strong><\/p>\n<ul>\n<li>Avoir compl\u00e9t\u00e9 le tutoriel\u00a0<a title=\"TIM.Flix.swift\" href=\"\/xcode\/index.php\/tim-flix-swift\/\">TIMFlix<\/a>\u00a0ou bien avoir une maitrise de l&rsquo;objet UITableView + segue + passage de param\u00e8tres entre les sc\u00e8nes d&rsquo;une app.<\/li>\n<li>Avoir compl\u00e9t\u00e9 le module\u00a0<a title=\"Projet: Aquarium \u2013 POO et protocoles\" href=\"\/xcode\/index.php\/projet-aquarium-poo-et-protocols\/\">POO sous \u00a0Swift<\/a>\u00a0ou bien avoir une maitrise des protocoles sous Swift.<\/li>\n<\/ul>\n<p>&nbsp;<br \/>\n&nbsp;<\/p>\n<hr \/>\n<p>&nbsp;<br \/>\nVid\u00e9o du r\u00e9sultat final:<br \/>\n<iframe loading=\"lazy\" title=\"Projet Post&#039;TIM\" width=\"700\" height=\"394\" src=\"https:\/\/www.youtube.com\/embed\/vEt18tY0-mg?feature=oembed\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture\" allowfullscreen><\/iframe><br \/>\n&nbsp;<\/p>\n<hr \/>\n<h1>Description du projet<\/h1>\n<p>Dans ce tutoriel, nous verrons comment construire une application qui permet la gestion d&rsquo;une liste de t\u00e2ches \u00e0 r\u00e9aliser &#8211; pr\u00e9sent\u00e9es dans un &lsquo;UITableView&rsquo; &#8211; , sous forme de m\u00e9mos \u00e9ditables.<br \/>\nLes &lsquo;t\u00e2ches&rsquo; seront lues et enregistr\u00e9es dans un fichier de propri\u00e9t\u00e9s, ce qui assurera leur p\u00e9rennit\u00e9 entre les chargements de l&rsquo;application.<br \/>\nL&rsquo;application proposera une liste de t\u00e2ches \u00e0 partir de laquelle il sera possible:<\/p>\n<ul>\n<li>d&rsquo;ajouter une nouvelle t\u00e2che<\/li>\n<li>de modifier la t\u00e2che courante<\/li>\n<li>d&rsquo;effacer la t\u00e2che courante<\/li>\n<li>de consulter le d\u00e9tail de la t\u00e2che courante.<\/li>\n<\/ul>\n<p>&nbsp;<\/p>\n<hr \/>\n<h1>Objectif principal<\/h1>\n<p>Savoir utiliser\u00a0un &lsquo;protocole&rsquo; sous Swift pour les passages de donn\u00e9es entre les classes des sc\u00e8nes.<br \/>\nExplication:<br \/>\nNous allons programmer un protocole, dans la classe de la sc\u00e8ne &lsquo;ajouter\/modifier&rsquo;, qui va permettre \u00e0 l&rsquo;abonn\u00e9, de recevoir les messages &lsquo;ajouterTache&rsquo; et &lsquo;modifierTache&rsquo; \u00a0avec en param\u00e8tre, des donn\u00e9es en provenance de la classe proposant le protocole.<br \/>\n&nbsp;<\/p>\n<h1>Objectifs secondaires<\/h1>\n<ul>\n<li>R\u00e9aliser une application qui permet la sauvegarde d&rsquo;informations sur l&rsquo;unit\u00e9 de stockage de l&rsquo;appareil iOS.<\/li>\n<li>Savoir programmer de la documentation en ligne.<\/li>\n<li>Savoir animer des propri\u00e9t\u00e9s de classes de type UIView.<\/li>\n<li>Savoir ajouter les ic\u00f4nes de l&rsquo;application.<\/li>\n<\/ul>\n<hr \/>\n<h1>1 &#8211; Le projet de d\u00e9part<\/h1>\n<p>&nbsp;<br \/>\n<span style=\"color: #ff0000;\"><strong>Action 1<\/strong><\/span>\u00a0&#8211; Ouvrons le projet de\u00a0d\u00e9part\u00a0et testons l&rsquo;app:\u00a0<a href=\"\/xcode\/wp-content\/uploads\/2014\/09\/PostTIM-version-swift-6.01-depart.zip\">Post&rsquo;TIM version swift 6.01 &#8211; depart<\/a><br \/>\n<iframe loading=\"lazy\" title=\"Projet - Post&#039;TIM-De\u0301part\" width=\"700\" height=\"394\" src=\"https:\/\/www.youtube.com\/embed\/GA8a_7hRnmE?feature=oembed\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture\" allowfullscreen><\/iframe><br \/>\nRemarquons que les modifications, ainsi que l&rsquo;ajout d&rsquo;une nouvelle t\u00e2che, ne sont pas enregistr\u00e9s.<br \/>\n&nbsp;<\/p>\n<blockquote><p><span style=\"color: #008080;\"><strong>Astuce<\/strong><\/span>: Pour tester une sc\u00e8ne du storyboard, non accessible par navigation, renseigner sa propri\u00e9t\u00e9 &lsquo;<strong>is initial View Controller<\/strong>&lsquo;.<\/p><\/blockquote>\n<p>&nbsp;<br \/>\n<span style=\"color: #ff0000;\"><strong>Action 1.01<\/strong><\/span>\u00a0&#8211; Analysons le sch\u00e9ma de d\u00e9part:<br \/>\n<a href=\"\/xcode\/wp-content\/uploads\/2014\/09\/Post-TIM_-_projet_de_depart-schema1.swift_.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-2337\" src=\"\/xcode\/wp-content\/uploads\/2014\/09\/Post-TIM_-_projet_de_depart-schema1.swift_.png\" alt=\"Post-TIM_-_projet_de_depart-schema1.swift\" width=\"1701\" height=\"675\" \/><\/a><br \/>\n&nbsp;<\/p>\n<hr \/>\n<h2>1.1 &#8211; Animation de propri\u00e9t\u00e9s<\/h2>\n<p>La classe UIView propose la m\u00e9thode de classe\u00a0<strong>animateWithDuration()<\/strong>. \u00a0Cette m\u00e9thode permet d&rsquo;animer plusieurs des propri\u00e9t\u00e9s des classes d\u00e9riv\u00e9es de UIView. \u00a0Par exemple, unUILabel.alpha, unUIImageView.center.y, &#8230;<br \/>\nLa m\u00e9thode \u00a0<strong>animateWithDuration()<\/strong> utilise la technique\u00a0des blocs pour soumettre, \u00e0 un fil d&rsquo;ex\u00e9cution (<a href=\"http:\/\/fr.wikipedia.org\/wiki\/Thread_(informatique)\"><b style=\"color: #252525;\">thread<\/b><\/a>), \u00a0les instructions d&rsquo;animation.<br \/>\nVoici sa signature:<\/p>\n<blockquote><p>UIView.animateWithDuration(<br \/>\n<span style=\"color: #008080;\">_ <strong>duration<\/strong><\/span>: NSTimeInterval,<br \/>\n<strong><span style=\"color: #008080;\">\/\/ delay<\/span><\/strong>: NSTimeInterval,<br \/>\n<strong><span style=\"color: #008080;\">\/\/ options<\/span><\/strong>: UIViewAnimationOptions,<br \/>\n<strong><span style=\"color: #008080;\">animations<\/span><\/strong>: () -&gt; Void,<br \/>\n<strong><span style=\"color: #008080;\">completion<\/span><\/strong>: ((Bool) -&gt; Void)?<br \/>\n)<\/p><\/blockquote>\n<p>Voici un exemple d&rsquo;utilisation:<\/p>\n<pre class=\"lang:swift decode:true\">logo.alpha = 0\nUIView.animateWithDuration(\n   2.0,\n   animations: {\n                  self.logo.alpha = 1 \/\/ il faut utiliser 'self.' dans un bloc\n               }, \/\/ animations:\n   completion: { terminee in  \/\/ la signature de completion indique un param\u00e8tre de type Bool\n                  println(\"L'animation de logo.alpha est termin\u00e9e\")\n               } \/\/ completion:\n) \/\/ UIView.animateWithDuration<\/pre>\n<p>&nbsp;<\/p>\n<h1>Nous allons animer plusieurs \u00e9l\u00e9ments de la sc\u00e8ne Intro.<\/h1>\n<p><span style=\"color: #ff0000;\"><strong>Action 1.1.1<\/strong><\/span> &#8211; Ajoutons le code suivant, \u00e0 la m\u00e9thode <strong>viewDidLoad<\/strong> de la classe <strong>Intro<\/strong>:<\/p>\n<pre class=\"lang:swift decode:true\">        titre1.alpha = 0;\n        titre2.alpha = 0;\n        logo.alpha   = 0;\n        logo.center.y = view.bounds.height      \/\/ Placer le centre du logo au bas de l'\u00e9cran.\n        \/\/ logo.center.y = view.frame.height    \/\/ Placer le centre du logo au bas de la view.\n        \/\/ Rappel: Il faut toujours pr\u00e9ciser le contexte des instances, dans un bloc. Par exemple, 'self.titre1'.\n        UIView.animateWithDuration(1,\n            delay: 0,\n            options: UIViewAnimationOptions.CurveEaseIn,\n            animations: {\n                            self.titre1.alpha   = 1\n                        },\n            completion: { terminee in\n                            UIView.animateWithDuration( 2.0,\n                                                        animations: {\n                                                                        self.titre2.alpha = 1\n                                                                        self.logo.alpha   = 1\n                                                                        self.logo.center.y = self.titre2.center.y + self.titre2.frame.height\n                                                                    }, \/\/ animations:\n                                                        completion: { terminee in\n                                                                         println(\"Animation de logo.alpha termin\u00e9e\")\n                                                                     } \/\/ completion:\n                            ) \/\/ UIView.animateWithDuration\n                        } \/\/ completion:\n        ) \/\/ UIView.animateWithDuration<\/pre>\n<p><span style=\"color: #ff0000;\"><strong>Note<\/strong><\/span>: Il faut mettre en commentaire:\u00a0self.performSegueWithIdentifier(\u00ab\u00a0versTaches\u00a0\u00bb, sender: self) situ\u00e9 dans la m\u00e9thode virewDidLoad()<\/p>\n<blockquote><p>&nbsp;<br \/>\n<strong><span style=\"color: #008080;\">Aide m\u00e9moire: \u00a0<\/span><\/strong><br \/>\nDans un bloc de code, \u00a0il faut toujours pr\u00e9ciser le contexte des m\u00e9thodes et des propri\u00e9t\u00e9s.<br \/>\nPar exemple,<br \/>\n<strong><span style=\"color: #ff0000;\">self<\/span><\/strong>.titre1<br \/>\n<strong><span style=\"color: #ff0000;\">self<\/span><\/strong>.uneM\u00e9thode()<\/p><\/blockquote>\n<p>&nbsp;<\/p>\n<hr \/>\n<h1>1.1.2 &#8211; Utilisation de GCD pour soumettre un bloc de code<\/h1>\n<p>&nbsp;<br \/>\n<a href=\"https:\/\/developer.apple.com\/LIBRARY\/ios\/documentation\/Performance\/Reference\/GCD_libdispatch_Ref\/index.html\"><strong>Grand Central Dispatch<\/strong><\/a>\u00a0(GCD) permet la gestion des fils d&rsquo;ex\u00e9cution (threads).<br \/>\n&nbsp;<br \/>\nNous avons vu, dans d&rsquo;autres projets, \u00a0comment programmer l&rsquo;ex\u00e9cution d&rsquo;une fonction suite \u00e0 un d\u00e9lai.<br \/>\nPar exemple,<br \/>\npasser de la sc\u00e8ne d&rsquo;introduction \u00e0 la sc\u00e8ne principale d&rsquo;un projet.<br \/>\nCeci \u00e9tait r\u00e9alis\u00e9 gr\u00e2ce \u00e0 la classe NSTimer.<br \/>\n&nbsp;<br \/>\nIl est possible d&rsquo;obtenir le m\u00eame r\u00e9sultat en utilisant les fonctions de <a href=\"https:\/\/developer.apple.com\/LIBRARY\/ios\/documentation\/Performance\/Reference\/GCD_libdispatch_Ref\/index.html\"><strong>Grand Central Dispatch<\/strong><\/a> (GCD).<br \/>\n&nbsp;<br \/>\nAutre r\u00e9f\u00e9rence: <a href=\"http:\/\/www.raywenderlich.com\/60749\/grand-central-dispatch-in-depth-part-1\">RW<\/a><br \/>\n&nbsp;<br \/>\n<span style=\"color: #ff0000;\"><strong>Action 1.1.2<\/strong> <\/span>&#8211; Ajoutons le code suivant, permettant de lancer un segue apr\u00e8s un d\u00e9lai, \u00a0\u00e0 la m\u00e9thode <strong>viewDidLoad<\/strong> de la classe <strong>Intro<\/strong>:<\/p>\n<pre class=\"lang:swift decode:true\">        \/\/ Utilisation de GrandCentralDispatch (GCD) pour placer en attente un 'performSegueWithIdentifier'\n        \/\/ R\u00e9f\u00e9rence: http:\/\/www.raywenderlich.com\/60749\/grand-central-dispatch-in-depth-part-1\n        let delaiEnSecondes:UInt64 = 2\n        let delaiEnNanoSecondes = Int64(delaiEnSecondes * NSEC_PER_SEC)  \/\/ nanoSec = 10e-9 sec\n        let deltaTemps = dispatch_time(DISPATCH_TIME_NOW, delaiEnNanoSecondes)\n        dispatch_after(deltaTemps, dispatch_get_main_queue(),\n            {\n                self.performSegueWithIdentifier(\"versTaches\", sender: self)\n            }\n        ) \/\/ dispatch_after<\/pre>\n<p><span style=\"color: #ff0000;\"><strong>Action 1.1.3<\/strong>\u00a0<\/span>&#8211; Testons l&rsquo;application<br \/>\n&nbsp;<\/p>\n<hr \/>\n<h2>1.2 &#8211; Activer la suppression des UITableViewCell sur &lsquo;swap&rsquo;.<\/h2>\n<p>&nbsp;<br \/>\nLe protocole <strong>UITableViewDataSource<\/strong> propose la m\u00e9thode &lsquo;<strong>commitEditingStyle<\/strong>&lsquo;.<br \/>\nCette derni\u00e8re permet, en autres choses, \u00a0d&rsquo;activer la suppression d&rsquo;une cellule sur glissement horizontal.<br \/>\nIl suffit d&rsquo;ajouter la m\u00e9thode\u00a0&lsquo;<strong>commitEditingStyle<\/strong>&lsquo; pour qu&rsquo;un glissement, sur une <strong>UITableViewCell<\/strong>, propose des op\u00e9rations sur la cellule.<br \/>\n&nbsp;<br \/>\n<span style=\"color: #ff0000;\"><strong>Action 1.2<\/strong><\/span>\u00a0&#8211; Ajoutons la m\u00e9thode suivante \u00e0 la classe &lsquo;<strong>VCNotes<\/strong>&lsquo;<\/p>\n<pre class=\"toolbar:1 lang:default decode:true\">    func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {\n         if (editingStyle == UITableViewCellEditingStyle.Delete) {\n            \/\/ Effacer, de tableauDesTaches,\n            \/\/ l'\u00e9l\u00e9ment correspondant \u00e0 la cellule courante\n            tableauDesTaches.removeObjectAtIndex(indexPath.row)\n            \/\/ Enregistrer le tableau dans le fichier.plist\n            updatePlist()\n            \/\/ Actualiser le UITableView\n            tableView.reloadData()\n        } \/\/ FIN -&gt; editingStyle == delete\n    } \/\/ ### FIN -&gt; commitEditingStyle<\/pre>\n<h2><\/h2>\n<p><span style=\"color: #ff0000;\"><strong>Action 1.2b<\/strong><\/span>\u00a0&#8211; Testons le glissement (swap) sur une des cellules du UITableView:<br \/>\n&nbsp;<br \/>\n<a href=\"\/xcode\/wp-content\/uploads\/2013\/11\/PostTIM-delete.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-658\" src=\"\/xcode\/wp-content\/uploads\/2013\/11\/PostTIM-delete.png\" alt=\"PostTIM-delete\" width=\"457\" height=\"412\" \/><\/a><br \/>\n&nbsp;<br \/>\n&nbsp;<\/p>\n<hr \/>\n<h2>1.3 &#8211;\u00a0Utiliser un &lsquo;NSDateFormatter&rsquo;\u00a0pour afficher une date en heure locale&#8230;<\/h2>\n<p>&nbsp;<br \/>\nSi nous ex\u00e9cutons l&rsquo;application, nous allons remarquer que l&rsquo;heure affich\u00e9e des t\u00e2ches ne correspond pas aux donn\u00e9es du fichier &lsquo;listeDesTaches.plist&rsquo;. \u00a0Cel\u00e0 s&rsquo;explique par le fait qu&rsquo;une date est localis\u00e9e au fuseau horaire &lsquo;UCT&rsquo; lors de sa conversion vers un NSString.<br \/>\n&nbsp;<br \/>\n<a href=\"\/xcode\/wp-content\/uploads\/2013\/11\/POSTTIM-date-UCT.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-655\" src=\"\/xcode\/wp-content\/uploads\/2013\/11\/POSTTIM-date-UCT.png\" alt=\"POSTTIM-date-UCT\" width=\"844\" height=\"385\" \/><\/a><br \/>\n<span style=\"color: #ff0000;\"><strong>Note<\/strong><\/span>: Utiliser le code suivant pour afficher la date:<\/p>\n<blockquote><p>cell.<span style=\"color: #539aa4;\">date<\/span>.<span style=\"color: #703daa;\">text<\/span> = (<span style=\"color: #539aa4;\">tableauDesTaches<\/span>[indexPath.<span style=\"color: #703daa;\">row<\/span>][<span style=\"color: #c91b13;\">\u00ab\u00a0date\u00a0\u00bb<\/span>]! <span style=\"color: #c32275;\">as<\/span> <span style=\"color: #6122ae;\">NSDate<\/span>).<span style=\"color: #703daa;\">description<\/span><\/p><\/blockquote>\n<p><span style=\"color: #703daa;\">\u00a0<\/span><br \/>\nL&rsquo;utilisation de la classe &lsquo;<strong>NSDataFormatter<\/strong>&lsquo; va permettre d&rsquo;utiliser le fuseau horaire de l&rsquo;appareil lors de la conversion. \u00a0De plus, il sera possible de programmer les \u00e9l\u00e9ments de date \u00e0 afficher. \u00a0Par exemple, le nom du jour (lundi) + le num\u00e9ro du mois + HH:MM, &#8230;<br \/>\n<strong>Voir le site\u00a0<a href=\"http:\/\/userguide.icu-project.org\/formatparse\/datetime\">suivant<\/a>\u00a0pour les commandes de formatage d&rsquo;une date.<\/strong><br \/>\n&nbsp;<br \/>\n<span style=\"color: #ff0000;\"><strong>Action 1.3<\/strong><\/span>\u00a0&#8211; \u00a0Ajoutons le code suivant \u00e0 la m\u00e9thode &lsquo;<strong>cellForRowAtIndexPath<\/strong>&lsquo; de la classe &lsquo;<strong>VCNotes<\/strong>&lsquo;<\/p>\n<pre class=\"toolbar:1 lang:default mark:6-9,11 decode:true\">        let uneDate = tableauDesTaches[indexPath.row][\"date\"]! as NSDate  \/\/ 1 - Obtenir la date de la t\u00e2che courante\n        let unFormateurDeDate = NSDateFormatter()                         \/\/ 2 - Cr\u00e9er un formateur de date\n        unFormateurDeDate.dateFormat = \"yyyy.MM.dd HH:mm\"                 \/\/ 3 - Pr\u00e9ciser le format de date d\u00e9sir\u00e9\n        let dateMiseEnForme = unFormateurDeDate.stringFromDate(uneDate)   \/\/ 4 - Obtenir, en chaine de caract\u00e8res, la date format\u00e9e\n        cell.date.text = dateMiseEnForme;                                 \/\/ 5 - Afficher dans la cellule courante\n<\/pre>\n<p>&nbsp;<br \/>\n<span style=\"color: #ff0000;\"><strong>Action 1.3b<\/strong><\/span>\u00a0&#8211; Testons l&rsquo;application et observons maintenant le format des dates.<br \/>\n<a href=\"\/xcode\/wp-content\/uploads\/2013\/11\/POSTTIM-date-locale.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-659\" src=\"\/xcode\/wp-content\/uploads\/2013\/11\/POSTTIM-date-locale.png\" alt=\"POSTTIM-date-locale\" width=\"971\" height=\"369\" \/><\/a><br \/>\n&nbsp;<\/p>\n<hr \/>\n<h1>1.4 &#8211; D\u00e9terminer quelle est la cellule qui a d\u00e9clench\u00e9e le &lsquo;segue&rsquo;<\/h1>\n<p><strong>Note<\/strong>: voir\u00a01.5 en premier.<br \/>\nIl y a deux &lsquo;<strong>UIButton<\/strong>&lsquo;s dans le mod\u00e8le de la cellule personnalis\u00e9e du projet.<br \/>\nUn d\u00e9placement &lsquo;segue&rsquo; pourra donc \u00eatre\u00a0d\u00e9clench\u00e9 par le bouton &lsquo;<strong>ajouter<\/strong>&lsquo; ou le bouton &lsquo;<strong>consulter<\/strong>&lsquo;.<br \/>\nDans les deux cas, \u00a0il y aura ex\u00e9cution de la m\u00e9thode &lsquo;<strong>prepareForSegue<\/strong>&lsquo; et le bouton s\u00e9lectionn\u00e9 sera pass\u00e9 en param\u00e8tre.<br \/>\n<span style=\"color: #ff0000;\">Nous ne recevrons pas la cellule o\u00f9 est survenu l&rsquo;\u00e9v\u00e9nement. \u00a0<\/span>Il ne sera donc pas possible d&rsquo;interroger le UITableView sur la position de la cellule re\u00e7ue.<br \/>\nIl est par contre possible d&rsquo;obtenir la position d&rsquo;une cellule en fonction du point d&rsquo;encrage (origin) d&rsquo;un des objets pr\u00e9sent dans le UITableView.<br \/>\n<strong>Note<\/strong>: Par default, le point d&rsquo;encrage d&rsquo;un objet se trouve au centre de l&rsquo;objet.<br \/>\n&nbsp;<br \/>\n<span style=\"color: #ff0000;\"><strong>Action 1.4<\/strong>\u00a0<\/span>&#8211; Ajoutons le code suivant \u00e0 la m\u00e9thode &lsquo;<strong>prepareForSegue<\/strong>&lsquo; de la classe &lsquo;<strong>VCNotes<\/strong>&lsquo;.<\/p>\n<pre class=\"toolbar:1 lang:default mark:10-12 decode:true\">        let button = sender as UIButton\n        let buttonFrame = button.convertRect(button.bounds, toView:self.tableView)\n        let indexPath   = self.tableView.indexPathForRowAtPoint(buttonFrame.origin)<\/pre>\n<p>&nbsp;<\/p>\n<hr \/>\n<h1>1.5 \u00a0&#8211; D\u00e9terminer la destination du &lsquo;segue&rsquo;<\/h1>\n<p>&nbsp;<br \/>\nLa sc\u00e8ne <strong>Notes<\/strong> poss\u00e8de trois liens de type &lsquo;segue&rsquo;.<br \/>\nIl n&rsquo;y a qu&rsquo;une seule m\u00e9thode &lsquo;<strong>prepareForSegue<\/strong>&lsquo; par classe de sc\u00e8ne.<br \/>\nPar contre, en v\u00e9rifiant le param\u00e8tre &lsquo;<strong>segue.identifier<\/strong>&lsquo;, il sera possible de d\u00e9terminer la destination.<br \/>\nVoici un exemple:<\/p>\n<pre class=\"lang:swift mark:3,8 decode:true\">override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject\n     if segue.identifier == \"modifier\" {\n         \/\/ Pointer sur l'instance la sc\u00e8ne de destination\n         \/\/ Passer les donn\u00e9es \u00e0 la sc\u00e8ne de destination\n         println(\"Segue vers 'modifier' avec le d\u00e9tail de l'indice 'n' du tableau\")\n     } \/\/ versAjouter\n     if segue.identifier == \"detail\" {\n         \/\/ Pointer sur l'instance la sc\u00e8ne de destination\n         \/\/ Passer les donn\u00e9es \u00e0 la sc\u00e8ne de destination\n         println(\"Segue vers 'detail' avec le d\u00e9tail de l'indice 'n' du tableau\")\n     } \/\/ VersDetail\n        ...\n} \/\/ prepareForSegue\n<\/pre>\n<p><strong>Note<\/strong>: Tester cet exemple en laboratoire avec le contenu de 1.4.<br \/>\n&nbsp;<br \/>\n<span style=\"color: #ff0000;\"><strong>Action 1.5<\/strong>\u00a0<\/span>&#8211; Ajoutons le code suivant \u00e0 la m\u00e9thode &lsquo;<strong>prepareForSegue<\/strong>&lsquo; de la classe &lsquo;<strong>VCNotes<\/strong>&lsquo;:<\/p>\n<pre class=\"toolbar:1 lang:default decode:true\">        \/\/ Tester si 'segue' est = 'ajouter'\n        if segue.identifier == \"ajouter\" {\n            let vers = segue.destinationViewController as VCAjouterTache\n            \/\/ *********************************************************************************\n            \/\/ \u00c0 observer\n            \/\/ TODO: - Action 3.4b - Segue Ajouter: Renseigner le d\u00e9l\u00e9gu\u00e9\n            \/\/ ---------------------------------------------------------------------------------\n            \/\/\/ vers.delegate = self;\n            \/\/ ---------------------------------------------------------------------------------\n            vers.modeAjouter = true;\n            NSLog(\"Transition vers %@\", segue.identifier);\n        } \/\/ segue.identifier == \"ajouter\"\n        \/\/ Tester si 'segue' est = 'modifier'\n        if segue.identifier == \"modifier\"{\n            let vers = segue.destinationViewController as VCAjouterTache\n            \/\/ *********************************************************************************\n            \/\/ \u00c0 observer\n            \/\/ TODO: Action 3.5b - Segue modifier: Renseigner le d\u00e9l\u00e9gu\u00e9\n            \/\/ ---------------------------------------------------------------------------------\n            \/\/\/  vers.delegate = self;\n            \/\/ ---------------------------------------------------------------------------------\n            vers.modeAjouter = false\n            vers.detailTache = Tache(detail: tableauDesTaches[indexPath!.row] as NSDictionary)\n            \/\/ sauvegarder la s\u00e9lection courante pour le retour de modifierTache\n            indiceTacheCourante = indexPath!.row;\n            NSLog(\"Transition vers %@ avec indice: %d\", segue.identifier, indexPath!.row);\n        }  \/\/ segue.identifier == \"modifier\"\n        \/\/ Tester si 'segue' est = 'detail'\n        if segue.identifier == \"detail\"{\n            let vers = segue.destinationViewController as VCDetail\n            vers.detailTache = Tache(detail: tableauDesTaches[indexPath!.row] as NSDictionary)\n            NSLog(\"Transition vers %@ avec indice: %d\", segue.identifier, indexPath!.row);\n        } \/\/ segue.identifier == \"detail\"<\/pre>\n<p>&nbsp;<br \/>\n<span style=\"color: #ff0000;\"><strong>Action 1.5b<\/strong><\/span> &#8211; <strong><span style=\"color: #ff0000;\">Faire les TODO: des fichiers VCDetail et\u00a0VCAjouterTache. \u00a0<\/span><\/strong><br \/>\n<span style=\"color: #ff0000;\"><strong>Action 1.5b<\/strong><\/span>\u00a0&#8211; Testons l&rsquo;application<br \/>\n<iframe loading=\"lazy\" title=\"Projet - Post&#039;TIM-E\u0301tape 1.5\" width=\"700\" height=\"394\" src=\"https:\/\/www.youtube.com\/embed\/m89nz1KSrFg?feature=oembed\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture\" allowfullscreen><\/iframe><br \/>\n&nbsp;<\/p>\n<hr \/>\n<h1>2 \u00a0&#8211; Mise en place du protocole\u00a0tacheDelegate<\/h1>\n<p><span style=\"color: #ff0000;\"><strong>Note<\/strong><\/span>:\u00a0\u00a0Pour une explication d\u00e9taill\u00e9e de la mise en place d&rsquo;un protocole, voir le laboratoire <a title=\"Projet: Aquarium \u2013 POO et protocoles\" href=\"\/xcode\/index.php\/projet-aquarium-poo-et-protocols\/\">Aquarium<\/a>.<br \/>\nDans le projet de d\u00e9part, la classe\u00a0<strong>VCAjouterTache<\/strong> propose d\u00e9j\u00e0 le protocole &lsquo;<strong>tacheDelegate<\/strong>&lsquo; avec les m\u00e9thodes &lsquo;<strong>ajouterTache<\/strong>&lsquo; et &lsquo;<strong>modifierTache<\/strong>&lsquo;.<br \/>\nNous utiliserons ce protocole pour retourner les donn\u00e9es modifi\u00e9es vers la classe de la sc\u00e8ne <strong>Notes<\/strong>.<\/p>\n<h2><\/h2>\n<h2>Rappel des \u00e9tapes de mise en place d&rsquo;un protocole:<\/h2>\n<p>&nbsp;<\/p>\n<h2>2.1a et 2.1b &#8211; D\u00e9claration\u00a0du protocole &lsquo;tacheDelegate&rsquo;<\/h2>\n<p><span style=\"color: #ff0000;\"><strong>Action 2.1<\/strong>\u00a0<\/span>&#8211; Observons\u00a0le code suivant du\u00a0fichier \u00a0&lsquo;VCAjouterTache&rsquo;.<\/p>\n<pre class=\"toolbar:1 lang:default decode:true\">\/\/\/ 2.1a - D\u00e9claration du protocole\nprotocol tacheDelegate {\n    \/**\n        Retourne, au d\u00e9l\u00e9gu\u00e9 du protocole tacheDelegate, la t\u00e2che \u00e0 ajouter.\n        :param: instance de la classe Tache\n    *\/\n    func ajouterTache(detailInfo:Tache)\n    \/**\n        Retourne, au d\u00e9l\u00e9gu\u00e9 du protocole tacheDelegate, la t\u00e2che modifi\u00e9e.\n        :param: instance de la classe Tache\n    *\/\n    func modifierTache(detailInfo:Tache)\n} \/\/ protocol tacheDelegate\n    \/\/\/ 2.1b - Propri\u00e9t\u00e9 pour le del\u00e9gu\u00e9 du protocole tacheDelegate.\n    var delegate:tacheDelegate?\n<\/pre>\n<p>&nbsp;<\/p>\n<h2>2.2 &#8211; Programmer l&rsquo;appel des m\u00e9thodes du protocole (gestion)<\/h2>\n<p>L&rsquo;appel d&rsquo;une m\u00e9thode d&rsquo;un protocole, impl\u00e9ment\u00e9e dans la classe du d\u00e9l\u00e9gu\u00e9, \u00a0se fait en utilisant la syntaxe suivante: <strong>delegate?uneM\u00e9thodeDuProtocole()<\/strong>.<br \/>\n<strong>uneM\u00e9thodeDuProtocole()<\/strong> sera ex\u00e9cut\u00e9e que si &lsquo;<strong>delegate<\/strong>&lsquo; n&rsquo;est pas <span style=\"color: #0000ff;\">nil<\/span>.<br \/>\n&nbsp;<br \/>\n<span style=\"color: #ff0000;\"><strong>Action 2.2<\/strong>\u00a0<\/span>&#8211; Observons\u00a0le code suivant du\u00a0fichier \u00a0&lsquo;VCAjouterTache&rsquo;.<\/p>\n<pre class=\"toolbar:1 lang:default decode:true\">        \/\/ Si en modeAjouter\n        if modeAjouter {\n            delegate?.ajouterTache(info)\n        }  \/\/ modeAjouter\n        else \/\/ alors c'est 'modeModifier'\n        {\n            self.delegate?.modifierTache(info)\n        }  \/\/ modeModifier<\/pre>\n<p>Le protocole de la classe &lsquo;VCAjouterTache&rsquo; est maintenant en place. \u00a0Par contre, s&rsquo;il n&rsquo;y a pas de d\u00e9l\u00e9gu\u00e9, les m\u00e9thodes du protocole ne seront pas ex\u00e9cut\u00e9es.<br \/>\n&nbsp;<\/p>\n<hr \/>\n<h1>3.3 &#8211; Souscrire (abonnement) au protocole tacheDelegate<\/h1>\n<p><span style=\"color: #ff0000;\"><strong>Note<\/strong><\/span>: La num\u00e9rotation passe \u00e0 3.x car les \u00e9tapes suivantes sont r\u00e9alis\u00e9es dans la classe &lsquo;VCNotes&rsquo;.<br \/>\n<span style=\"color: #ff0000;\"><b>Action 3.3<\/b><\/span>&#8211; Observons\u00a0le code suivant de la classe\u00a0&lsquo;<strong>VCNotes<\/strong>&lsquo;<\/p>\n<pre class=\"toolbar:1 lang:default decode:true\">class VCNotes: UIViewController, UITableViewDataSource, tacheDelegate {\n  ...<\/pre>\n<p><span style=\"color: #ff0000;\"><strong>Note<\/strong><\/span>: Il faut enlever le commentaire \/* tacheDelegate *\/ dans le code source. Cela provoquera l&rsquo;erreur &lsquo;VCNotes&rsquo; non conforme au protocole &lsquo;tacheDelegate&rsquo;.<br \/>\n\u00c0 partir de cette \u00e9tape, il faut\u00a0maintenant programmer les m\u00e9thodes \u00a0&lsquo;ajouterTache&rsquo; et &lsquo;modifierTache&rsquo; du protocole &lsquo;tacheDelegate&rsquo; dans\u00a0la classe &lsquo;Notes&rsquo;.<br \/>\n&nbsp;<\/p>\n<h2>3.4a &#8211; Programmation de la m\u00e9thode &lsquo;ajouterTache&rsquo;<\/h2>\n<p><span style=\"color: #ff0000;\"><b><br \/>\nAction 3.4a\u00a0<\/b><\/span>&#8211; Ajoutons le code suivant au fichier &lsquo;VCNotes.m&rsquo;<\/p>\n<pre class=\"toolbar:1 lang:default decode:true\">    func ajouterTache(info:Tache){\n        NSLog(\"ajouterTache, info = %@\", info.tache);\n        \/\/ Ajouter au tableauTaches les donn\u00e9es re\u00e7ues.\n        tableauDesTaches.addObject(info.tacheToDictionary())\n        NSLog(\"tableauDesTaches ajouterTache = %@\", info.tacheToDictionary());\n        \/\/ Actualiser le UITableView\n        self.tableView.reloadData()\n        \/\/ Enregistrer le tableau dans le fichier.plist\n        updatePlist()\n    } \/\/ ### FIN -&gt; ajouterTache<\/pre>\n<h2><\/h2>\n<h2>3.4b &#8211; Renseigner la propri\u00e9t\u00e9 &lsquo;delegate&rsquo; pour la destination &lsquo;ajouter&rsquo;.<\/h2>\n<p><b><br \/>\n<span style=\"color: #ff0000;\">Action 3.4b\u00a0<\/span><\/b>&#8211; Observons\u00a0\u00a0le code suivant du\u00a0fichier &lsquo;VCNotes.m&rsquo;<\/p>\n<pre class=\"toolbar:1 lang:default mark:9 decode:true\">vers.delegate = self;<\/pre>\n<p><span style=\"color: #ff0000;\">\u00a0<strong><br \/>\n<\/strong><\/span><\/p>\n<h2>3.5a &#8211; Programmation de la m\u00e9thode &lsquo;modifierTache&rsquo;<\/h2>\n<p><b><br \/>\n<span style=\"color: #ff0000;\">Action 3.5a\u00a0<\/span><\/b>&#8211; Ajoutons\u00a0le code suivant au fichier &lsquo;VCNotes.m&rsquo;<\/p>\n<pre class=\"toolbar:1 lang:default decode:true\">   func modifierTache(info:Tache) {\n        NSLog(\"retour de la m\u00e9thode 'modifier', info = %@\", info.tache);\n        \/\/ Remplacer l'\u00e9l\u00e9ment courant du tableauTaches par les donn\u00e9es re\u00e7ues.\n        tableauDesTaches[indiceTacheCourante] = info.tacheToDictionary()\n        NSLog(\"tableauDesTaches \u00e9l\u00e9ment %d modifi\u00e9 = %@\", indiceTacheCourante, tableauDesTaches);\n        \/\/ Actualiser le UITableView\n        tableView.reloadData()\n        \/\/ Enregistrer tableauTaches dans le fichier 'listeDesTaches.plist'\n        updatePlist()\n    } \/\/ ### FIN -&gt; modifierTache<\/pre>\n<p>&nbsp;<\/p>\n<h2>\u00c9tape 3.5b &#8211; Renseigner la propri\u00e9t\u00e9 &lsquo;delegate&rsquo; pour la destination &lsquo;modifier&rsquo;.<\/h2>\n<p><span style=\"color: #ff0000;\"><b><br \/>\nAction 3.5b<\/b><\/span>&#8211; Observons\u00a0le code suivant du fichier &lsquo;VCNotes.m&rsquo;<\/p>\n<pre class=\"toolbar:1 lang:default mark:7 decode:true\">vers.delegate = self<\/pre>\n<p>&nbsp;<br \/>\n<strong><span style=\"color: #ff0000;\">Action 3.6<\/span>\u00a0<\/strong>&#8211; Testons l&rsquo;application.<br \/>\n&nbsp;<\/p>\n<hr \/>\n<h1>4 &#8211; Sauvegarder les donn\u00e9es dans l&rsquo;appareil<\/h1>\n<p>&nbsp;<br \/>\n<span style=\"color: #ff0000;\"><strong>Note<\/strong><\/span>: Le code est d\u00e9j\u00e0 pr\u00e9sent dans le projet de d\u00e9part. \u00a0Ce qui suit est un exercice de compr\u00e9hension de la technique n\u00e9cessaire pour \u00eatre en mesure d&rsquo;enregistrer des donn\u00e9es sur l&rsquo;appareil.<br \/>\n&nbsp;<\/p>\n<blockquote><p><span style=\"color: #008080;\"><strong>Aide m\u00e9moire:<\/strong><\/span><br \/>\nLes fichiers d&rsquo;une application, pr\u00e9sents dans le dossier d&rsquo;installation, \u00a0sont accessible en lecture seulement. \u00a0Pour qu&rsquo;une application puisse les modifier, il faut les copier vers un des dossiers de l&rsquo;utilisateur: Documents, Images, &#8230;<br \/>\n&nbsp;<\/p><\/blockquote>\n<p>\u00c9tape initiale &#8211; Au besoin, copier les fichiers, qui seront modifi\u00e9s par l&rsquo;application, du paquet de l&rsquo;installation (bundle) vers un dossier de l&rsquo;utilisateur.<br \/>\n<strong><span style=\"color: #ff0000;\">4.1<\/span><\/strong> &#8211; Si non pr\u00e9sent dans le dossier &lsquo;Documents&rsquo;, copier le fichier <strong>listeDesTaches.plist<\/strong>, livr\u00e9 avec l&rsquo;application, vers de dossier &lsquo;Documents&rsquo;<\/p>\n<pre class=\"lang:swift decode:true\">    \/\/ MARK: - Gestion de la listeDesTaches.plist\n    \/**\n        Envoyer une copie du ficher 'listeDesTaches.plist' vers le dossier 'Document'.\n        Raison: La version livr\u00e9e avec l'app est non modifiable.\n    *\/\n     func copierPlistVersDocuments() {\n        let filemanager = NSFileManager.defaultManager()\n        let documentsPath: AnyObject = NSSearchPathForDirectoriesInDomains(.DocumentDirectory,.UserDomainMask,true)[0]\n        let destinationPath = documentsPath.stringByAppendingString(\"\/listeDesTaches.plist\")\n        if !filemanager.fileExistsAtPath(destinationPath) {\n            let fileForCopy = NSBundle.mainBundle().pathForResource(\"listeDesTaches\",ofType:\"plist\")\n            filemanager.copyItemAtPath(fileForCopy!,toPath:destinationPath, error: nil)\n            println(\"La liste des t\u00e2ches a \u00e9t\u00e9 copi\u00e9e dans le dossier 'mes documents'\")\n        }\n        else{\n            println(\"La liste des t\u00e2ches est d\u00e9j\u00e0 dans le dossier 'mes documents'\")\n        }\n     } \/\/ copierPlistVersDocuments<\/pre>\n<p>&nbsp;<br \/>\n<span style=\"color: #ff0000;\"><strong>4.2<\/strong><\/span> &#8211; Lire les t\u00e2ches sauvegard\u00e9es \u00e0 partir du dossier &lsquo;Documents&rsquo;<\/p>\n<pre class=\"lang:swift decode:true \">    \/**\n    Lire le fichier 'listeDesTaches.plist' vers le tableau 'tableauDesTaches'\n    *\/\n    func lirePlist() {\n        let filemanager = NSFileManager.defaultManager()\n        let documentsPath : AnyObject = NSSearchPathForDirectoriesInDomains(.DocumentDirectory,.UserDomainMask,true)[0]\n        let destinationPath = documentsPath.stringByAppendingString(\"\/listeDesTaches.plist\")\n        tableauDesTaches = NSMutableArray(contentsOfFile: destinationPath)\n        NSLog(\"%@\", tableauDesTaches);\n    } \/\/ lirePlist()<\/pre>\n<p><span style=\"color: #ff0000;\"><strong>Note<\/strong><\/span>: \u00a0Il faudrait ajouter une validation sur la\u00a0lecture du fichier des donn\u00e9es.<br \/>\n&nbsp;<br \/>\n<span style=\"color: #ff0000;\"><strong>4.3<\/strong><\/span>\u00a0&#8211;\u00a0\u00c9crire les t\u00e2ches dans le dossier &lsquo;Document&rsquo;<\/p>\n<pre class=\"lang:swift decode:true\">    \/**\n        \u00c9crire le tableau 'tableauDesTaches' dans le fichier 'listeDesTaches.plist'\n    *\/\n    func updatePlist() {\n        let filemanager = NSFileManager.defaultManager()\n        let documentsPath : AnyObject = NSSearchPathForDirectoriesInDomains(.DocumentDirectory,.UserDomainMask,true)[0]\n        let destinationPath = documentsPath.stringByAppendingString(\"\/listeDesTaches.plist\")\n        tableauDesTaches.writeToFile(destinationPath, atomically:true)\n    }  \/\/ updatePlist()<\/pre>\n<p><span style=\"color: #ff0000;\"><strong>Note<\/strong><\/span>: \u00a0Il faudrait ajouter une validation sur l&rsquo;\u00e9criture\u00a0des donn\u00e9es dans\u00a0le fichier plist.<\/p>\n<h1><\/h1>\n<hr \/>\n<h1>5 &#8211; Documentation en ligne<\/h1>\n<p>&nbsp;<br \/>\nXcode propose des outils pour documenter, en ligne, les codes sources, les classes, les m\u00e9thodes, les propri\u00e9t\u00e9s.<br \/>\nLa documentation en ligne, des classes livr\u00e9es avec Xcode, est accessible soit par la s\u00e9quence <strong>alt+clic<\/strong>:<br \/>\n<a href=\"\/xcode\/wp-content\/uploads\/2014\/09\/doc-en-ligne.01.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-2368\" src=\"\/xcode\/wp-content\/uploads\/2014\/09\/doc-en-ligne.01.png\" alt=\"doc-en-ligne.01\" width=\"513\" height=\"221\" \/><\/a><br \/>\n&nbsp;<br \/>\nsoit par\u00a0l&rsquo;inspecteur d&rsquo;aide:<br \/>\n<a href=\"\/xcode\/wp-content\/uploads\/2014\/09\/doc-en-ligne.02.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-2369\" src=\"\/xcode\/wp-content\/uploads\/2014\/09\/doc-en-ligne.02.png\" alt=\"doc-en-ligne.02\" width=\"536\" height=\"303\" \/><\/a><br \/>\n&nbsp;<br \/>\nIl est aussi possible d&rsquo;obtenir de la documentation sur une m\u00e9thode ou un propri\u00e9t\u00e9 d&rsquo;une classe:<br \/>\n<a href=\"\/xcode\/wp-content\/uploads\/2014\/09\/doc-en-ligne.03.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-2370\" src=\"\/xcode\/wp-content\/uploads\/2014\/09\/doc-en-ligne.03.png\" alt=\"doc-en-ligne.03\" width=\"624\" height=\"590\" \/><br \/>\n<\/a><br \/>\n&nbsp;<\/p>\n<hr \/>\n<h1>5.1 Documentation de nos classes<\/h1>\n<p>&nbsp;<br \/>\nIl est possible de programmer le m\u00eame genre de documentation en ligne pour les classes de nos projets.<br \/>\n&nbsp;<br \/>\nPar exemple, sur compl\u00e9tion du code:<\/p>\n<ul>\n<li>Pour une classe<\/li>\n<\/ul>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-2371 size-full\" src=\"\/xcode\/wp-content\/uploads\/2014\/09\/doc-en-ligne.04.png\" alt=\"doc-en-ligne.04\" width=\"395\" height=\"155\" \/><br \/>\n&nbsp;<\/p>\n<ul>\n<li>\u00a0Une propri\u00e9t\u00e9<\/li>\n<\/ul>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-2373 size-full\" src=\"\/xcode\/wp-content\/uploads\/2014\/09\/doc-en-ligne.06.png\" alt=\"doc-en-ligne.06\" width=\"389\" height=\"233\" \/><br \/>\n&nbsp;<\/p>\n<ul>\n<li>Une m\u00e9thode<\/li>\n<\/ul>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-2374 size-full\" src=\"\/xcode\/wp-content\/uploads\/2014\/09\/doc-en-ligne.07.png\" alt=\"doc-en-ligne.07\" width=\"385\" height=\"233\" \/><br \/>\n&nbsp;<br \/>\nDocumentation en ligne d&rsquo;une classe personnalis\u00e9e<\/p>\n<ul>\n<li>Sur un <strong>alt+clic<\/strong>:<\/li>\n<\/ul>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-2372 size-full\" src=\"\/xcode\/wp-content\/uploads\/2014\/09\/doc-en-ligne.05.png\" alt=\"doc-en-ligne.05\" width=\"537\" height=\"145\" \/><br \/>\n&nbsp;<\/p>\n<ul>\n<li>Ou soit\u00a0par\u00a0l&rsquo;inspecteur d&rsquo;aide:<\/li>\n<\/ul>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-2375 size-full\" src=\"\/xcode\/wp-content\/uploads\/2014\/09\/doc-en-ligne.08.png\" alt=\"doc-en-ligne.08\" width=\"537\" height=\"205\" \/><br \/>\n&nbsp;<br \/>\n&nbsp;<\/p>\n<hr \/>\n<h1>5.2 &#8211; R\u00e9diger de la documentation en ligne<\/h1>\n<p>&nbsp;<br \/>\nPour r\u00e9diger de la documentation en ligne, il suffit d&rsquo;utiliser la syntaxe suivante:<\/p>\n<ul>\n<li>Une seule ligne de documentation<\/li>\n<\/ul>\n<blockquote><p>\/\/\/ Une description de ce qui suit &#8230;<br \/>\nvar unePropri\u00e9t\u00e9:Int<br \/>\n\/\/\/ Une description de ce qui suit &#8230;<br \/>\nvar uneAutrePropri\u00e9t\u00e9:String<\/p><\/blockquote>\n<p><span style=\"color: #ff0000;\"><strong>Note<\/strong><\/span>: Il faut utiliser trois &lsquo;\/&rsquo;.<br \/>\n<span style=\"color: #ff0000;\"><strong>Note<\/strong><\/span>: \u00a0Entre le commentaire et le code, il est possible d&rsquo;ins\u00e9rer des lignes vides mais pas de commentaires standards: \u00a0\/\/ Ceci est un commentaire standard.<br \/>\n&nbsp;<\/p>\n<ul>\n<li>Plusieurs lignes de documentation<\/li>\n<\/ul>\n<blockquote><p>\/**<br \/>\nDe la documentation<br \/>\nsur plusieurs<br \/>\nlignes&#8230;<br \/>\n*\/<br \/>\nfunc uneM\u00e9thodeDocument\u00e9e() {}<\/p><\/blockquote>\n<p><span style=\"color: #ff0000;\"><strong>Note<\/strong><\/span>: Il faut utiliser &lsquo;\/**&rsquo; pour ouvrir le commentaire.<br \/>\n&nbsp;<\/p>\n<ul>\n<li>Utilisation de mots cl\u00e9s pour d\u00e9finir des sections<\/li>\n<\/ul>\n<blockquote><p>\/**<br \/>\nTransformer les propri\u00e9t\u00e9s de la classe Tache en format NSDictionary<br \/>\n<span style=\"color: #008080;\"><strong>\u00a0 \u00a0 :param:<\/strong><\/span>\u00a0 Aucun<br \/>\n<span style=\"color: #008080;\"><strong>\u00a0 \u00a0 :returns:<\/strong><\/span> Tache en format NSDictionary<br \/>\nAuteur: \u00a0 Alain Boudreault<br \/>\nDate: \u00a0 \u00a0 \u00a0 2014.10.20<br \/>\nM-A-J:\u00a0 \u00a0 \u00a0 2014.10.21 &#8211; Ajout de la documentation en ligne.<br \/>\n*\/<br \/>\nfunc tacheToDictionary()<\/p><\/blockquote>\n<p><span style=\"color: #ff0000;\"><strong>Note<\/strong><\/span>: \u00a0Le mot cl\u00e9 est entre <span style=\"color: #008080;\"><strong>::<\/strong><\/span><br \/>\n<span style=\"color: #ff0000;\"><strong>Note<\/strong><\/span>: \u00a0Il doit y avoir au moins une ligne vide entre les sections.<br \/>\n<strong>R\u00e9sultat<\/strong>:<br \/>\n<img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-2379\" src=\"\/xcode\/wp-content\/uploads\/2014\/09\/docum-enligne-sections-2.png\" alt=\"docum-enligne-sections-2\" width=\"584\" height=\"278\" \/><\/p>\n<blockquote><p><span style=\"color: #008080;\"><strong>Pr\u00e9cision<\/strong><\/span>:<br \/>\nAu moment d&rsquo;\u00e9crire ce document (Xcode 6.1), la fonction de documentation en ligne, sous swift,\u00a0n&rsquo;\u00e9tait pas enti\u00e8rement impl\u00e9ment\u00e9e par Apple.<br \/>\nPlusieurs mots cl\u00e9s, pour les sous-sections, qui \u00e9taient disponibles en Objective-C ne le sont pas encore.<br \/>\nCette situation devrait \u00eatre corrig\u00e9e dans les prochaines versions de Xcode.<\/p><\/blockquote>\n<p><strong>En r\u00e9f\u00e9rence,<\/strong> voici une liste des mots cl\u00e9s, de sous-sections, disponibles en Objective-C<br \/>\n[table]<br \/>\nSection, Exemple<br \/>\n:brief:, :brief: Ceci est la description sommaire<br \/>\n:attention:,\u00a0:attention: \u00c0 l&rsquo;usage exclusif des \u00e9tudiants de TIM<br \/>\n:author:, :author:\u00a0Alain Boudreault<br \/>\n:bug:,:bug:\u00a0 La m\u00e9thode @b mangerDuPain retourne un lapin!<br \/>\n:copyright:,:copyright: 2014 &#8211; Alain Boudreault<br \/>\n:date:\u00a0,:date: 2014.10.27<br \/>\n:invariant:,:invariant: ..<br \/>\n:note:, :note: ..<br \/>\n:post:, :post: ..<br \/>\n:pre:,:pre: ..<br \/>\n:remarks:,:remarks: Voici des remarques &#8230;<br \/>\n:sa:,:sa: sa text<br \/>\n:see:,:see: see text<br \/>\n:since:,:since: depuis toujours<br \/>\n:todo:\u00a0,:todo: Corriger la m\u00e9thode @b mangerDuPain<br \/>\n:version:,:version: 1.0<br \/>\n:warning:,:warning: Ici la voix des mist\u00e9rons&#8230;<br \/>\n:result:,:result: result text<br \/>\n:return:,:return: return text<br \/>\n:returns:,:returns: returns text<br \/>\n:code::endcode:, Pour afficher un bloc de code<br \/>\n[\/table]<br \/>\n&nbsp;<br \/>\nExemple,<br \/>\n<a href=\"\/xcode\/wp-content\/uploads\/2014\/05\/xcode.docum_.enligne.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-792\" src=\"\/xcode\/wp-content\/uploads\/2014\/05\/xcode.docum_.enligne.png\" alt=\"xcode.docum.enligne\" width=\"478\" height=\"569\" \/><\/a><br \/>\n&nbsp;<br \/>\n&nbsp;<\/p>\n<hr \/>\n<h1>5.3 &#8211; Les marqueurs MARK:, TODO: et FIXME:<\/h1>\n<p>&nbsp;<br \/>\nLes marqueurs\u00a0MARK:, TODO: et FIXME: servent \u00e0\u00a0ins\u00e9rer des points d&rsquo;ancrage dans le code source. \u00a0Ces points d&rsquo;ancrage\u00a0permettent un acc\u00e8s rapide \u00e0 un section de notre code. \u00a0Apr\u00e8s d\u00e9finitions, il sont accessible via le\u00a0menu de saut (Jump Bar).<br \/>\n<img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-2377\" src=\"\/xcode\/wp-content\/uploads\/2014\/09\/jump-bar.png\" alt=\"jump-bar\" width=\"1176\" height=\"91\" \/><br \/>\n&nbsp;<br \/>\n<img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-2378\" src=\"\/xcode\/wp-content\/uploads\/2014\/09\/documentation-marqueurs.png\" alt=\"documentation-marqueurs\" width=\"549\" height=\"267\" \/><\/p>\n<hr \/>\n<h1>6.4 Exemple d&rsquo;une classe document\u00e9e<\/h1>\n<p>&nbsp;<br \/>\nVoici le code de la classe &lsquo;Tache&rsquo;. \u00a0Il est extrait du projet en cours.<br \/>\n&nbsp;<\/p>\n<pre class=\"lang:swift decode:true\">\/\/\n\/\/  Tache.swift\n\/\/  Post'TIM version swift\n\/\/\n\/\/  Cr\u00e9\u00e9 par Alain Boudreault le 20105.11.15\n\/\/  Copyright (c) 2014 Alain Boudreault. All rights reserved.\n\/\/\n\/\/  MARK: - Note importante!\n\/\/  ============================================================================================\n\/\/  \u00c0 l'usage exclusif des \u00e9tudiants et \u00e9tudiantes de\n\/\/  ============================================================================================\nimport Foundation\n\/\/ NOTE: un retour de chariot est requis entre les diff\u00e9rentes sections de la documentation.\n\/**\n    Classe pour regrouper les informations d'une t\u00e2che.\n    Propose un init permettant de construire une t\u00e2che \u00e0 partir d'un NSDictionary\n    :returns: une instance de la classe Tache.\n    :param: aucun\n    Auteur:   Alain Boudreault\n    Date:     2014.10.20\n*\/\nclass Tache {\n    \/\/\/ La date de la t\u00e2che.\n    var date:NSDate\n    \/\/\/ Le nom de la t\u00e2che.\n    var tache:String\n    \/\/\/ L'importance de la t\u00e2che, une valeur entre 1...9\n    var importance:String\n    \/\/\/ Un texte d\u00e9crivant la t\u00e2che.\n    var description:String  \/\/\/&lt; Un texte d\u00e9crivant la t\u00e2che.  \/\/ Syntaxe non fonctionnelle sous Swift.\n    \/**\n        Construire une tache vide.\n        :param: aucun\n    *\/\n    init () {\n        self.date           = NSDate()\n        self.description    = \"\"\n        self.importance     = \"\"\n        self.tache          = \"\"\n    } \/\/ init\n    \/**\n        Construire une tache \u00e0 partir de donn\u00e9es d'un dictionnaire.\n        :param: detail:NSDictionary contenant les cl\u00e9s \"date\", \"description\", \"importance\" et \"tache\"\n    *\/\n    init (detail:NSDictionary) {\n        self.date           = detail[\"date\"]        as NSDate\n        self.description    = detail[\"description\"] as String\n        \/\/ FIXME: Valider le contenu de detail[\"importance\"]\n        self.importance     = detail[\"importance\"]  as String\n        self.tache          = detail[\"tache\"]       as String\n    } \/\/ init\n    \/**\n        Transformer les propri\u00e9t\u00e9s de la classe Tache en format NSDictionary\n        :returns: Tache en format NSDictionary\n        Auteur:   Alain Boudreault\n        Date:       2014.10.20\n        M-A-J:      2014.10.21 - Ajout de la documentation en ligne.\n    *\/\n    func tacheToDictionary() -&gt; NSDictionary {\n        return NSDictionary(dictionary: [\"tache\":self.tache,\n            \"date\":self.date,\n            \"importance\":self.importance,\n            \"description\":self.description])\n    } \/\/ tacheToDictionary()\n    \/\/TODO: Ajouter une m\u00e9thode quiSuisJe()\n} \/\/ class Tache<\/pre>\n<p>&nbsp;<\/p>\n<hr \/>\n<h1>6 &#8211; Ajouter les ic\u00f4nes de l&rsquo;application<\/h1>\n<p>&nbsp;<br \/>\nPour ajouter des icons \u00e0 l&rsquo;application, il suffit de faire glisser des images, de la bonne taille, dans le panneau &lsquo;AppIcon&rsquo; du groupe &lsquo;Images.xcassets&rsquo;:<br \/>\n<a href=\"\/xcode\/wp-content\/uploads\/2014\/09\/post-tim.icon_.01b.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-2340\" src=\"\/xcode\/wp-content\/uploads\/2014\/09\/post-tim.icon_.01b.png\" alt=\"post-tim.icon.01b\" width=\"1184\" height=\"462\" \/><\/a><br \/>\n<span style=\"color: #ff0000;\"><strong>Note<\/strong><\/span>: \u00a0Il y a une s\u00e9rie d&rsquo;images, pouvant servir d&rsquo;icon, dans un des dossiers du projet de d\u00e9part.<br \/>\n&nbsp;<\/p>\n<h2>R\u00e9f\u00e9rence pour la taille des fichiers:<\/h2>\n<p><a href=\"\/xcode\/wp-content\/uploads\/2014\/09\/post-tim.icon_.02b.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-2341\" src=\"\/xcode\/wp-content\/uploads\/2014\/09\/post-tim.icon_.02b.png\" alt=\"post-tim.icon.02b\" width=\"565\" height=\"186\" \/><\/a><br \/>\n<strong><br \/>\nR\u00e9sultat sur l&rsquo;appareil:<\/strong><br \/>\n<img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-2382\" src=\"\/xcode\/wp-content\/uploads\/2014\/09\/changer-icon.01.png\" alt=\"changer-icon.01\" width=\"376\" height=\"690\" \/><br \/>\nDans spotlight:<br \/>\n<img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-2383\" src=\"\/xcode\/wp-content\/uploads\/2014\/09\/changer-icon.02.png\" alt=\"changer-icon.02\" width=\"377\" height=\"690\" \/><br \/>\n&nbsp;<\/p>\n<hr \/>\n<h1>6.1 Changer le titre le l&rsquo;application<\/h1>\n<p>Le titre de l&rsquo;application est tronqu\u00e9, sur le t\u00e9l\u00e9phone, car il est trop long.<br \/>\n&nbsp;<br \/>\n<img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-2384\" src=\"\/xcode\/wp-content\/uploads\/2014\/09\/changer-titre-app.01.png\" alt=\"changer-titre-app.01\" width=\"376\" height=\"149\" \/><br \/>\n&nbsp;<br \/>\nVoici comment le changer:<br \/>\n<img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-2385\" src=\"\/xcode\/wp-content\/uploads\/2014\/09\/changer-titre-app.02.png\" alt=\"changer-titre-app.02\" width=\"860\" height=\"326\" \/><br \/>\n&nbsp;<br \/>\n<img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-2386\" src=\"\/xcode\/wp-content\/uploads\/2014\/09\/changer-titre-app.03.png\" alt=\"changer-titre-app.03\" width=\"402\" height=\"72\" \/><br \/>\n&nbsp;<br \/>\n<strong>R\u00e9sultat sur l&rsquo;appareil:<\/strong><br \/>\n<img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-2387\" src=\"\/xcode\/wp-content\/uploads\/2014\/09\/changer-titre-app.04.png\" alt=\"changer-titre-app.04\" width=\"378\" height=\"150\" \/><br \/>\n&nbsp;<br \/>\nVoici qui compl\u00e8te le laboratoire Post&rsquo;TIM!<br \/>\n&nbsp;<br \/>\n<a href=\"\/xcode\/wp-content\/uploads\/2014\/09\/PostTIM-version-swift-6.01-solution.zip\">Post&rsquo;TIM version swift 6.01 &#8211; solution<br \/>\n<\/a><a href=\"\/xcode\/wp-content\/uploads\/2014\/09\/PostTIM-version-swift-6.1-solution.zip\">Post&rsquo;TIM version swift 6.1 &#8211; solution<\/a><a href=\"\/xcode\/wp-content\/uploads\/2014\/09\/PostTIM-version-swift-6.01-solution.zip\"><br \/>\n<\/a><\/p>\n<hr \/>\n<h5 style=\"text-align: right;\">Document pr\u00e9par\u00e9 par Alain Boudreault (c) 2013-2014 &#8211; version 2014.11.17<\/h5>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Passage de donn\u00e9es, par l&rsquo;utilisation d&rsquo;un\u00a0protocole &nbsp; Contenu Programmer un protocole pour le retour de donn\u00e9es vers une sc\u00e8ne ayant initi\u00e9 un segue. Documenter correctement les ent\u00eates de classes, les propri\u00e9t\u00e9s et les m\u00e9thodes (documentation en ligne) Utiliser le dossier &lsquo;Document&rsquo; pour enregistrer les donn\u00e9es d&rsquo;une application Enregistrer un NSArray dans un fichier de propri\u00e9t\u00e9s [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"footnotes":""},"class_list":["post-1660","page","type-page","status-publish","hentry"],"_links":{"self":[{"href":"https:\/\/ve2cuy.com\/xcode\/wp-json\/wp\/v2\/pages\/1660","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/ve2cuy.com\/xcode\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/ve2cuy.com\/xcode\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/ve2cuy.com\/xcode\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/ve2cuy.com\/xcode\/wp-json\/wp\/v2\/comments?post=1660"}],"version-history":[{"count":0,"href":"https:\/\/ve2cuy.com\/xcode\/wp-json\/wp\/v2\/pages\/1660\/revisions"}],"wp:attachment":[{"href":"https:\/\/ve2cuy.com\/xcode\/wp-json\/wp\/v2\/media?parent=1660"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}