{"id":1656,"date":"2014-09-13T09:42:38","date_gmt":"2014-09-13T13:42:38","guid":{"rendered":"http:\/\/tim.cstj.qc.ca\/cours\/xcode\/wp\/?page_id=1656"},"modified":"2014-09-13T09:42:38","modified_gmt":"2014-09-13T13:42:38","slug":"projet-les-rottentomatoes-version-swift","status":"publish","type":"page","link":"https:\/\/ve2cuy.com\/xcode\/projet-les-rottentomatoes-version-swift\/","title":{"rendered":"Projet: Les RottenTomatoes &#8211; version Swift"},"content":{"rendered":"<h1>Utilisation d&rsquo;une &lsquo;API&rsquo; web<\/h1>\n<p><strong><span style=\"color: #339966;\">R\u00e9vision du 2015.11.16 &#8211; conversion vers Xcode 6.4<\/span><\/strong><br \/>\nDans le tutoriel\u00a0<a href=\"\/xcode\/index.php\/labo\/timflix-delegation-et-uitableview-personnalisee\/\">TIMFlix<\/a>, nous avons construit une application qui affichait une liste de vid\u00e9os \u00e0 l&rsquo;int\u00e9rieur d&rsquo;un UITableView.<br \/>\nLes informations des vid\u00e9os, ainsi que l&rsquo;image des affiches, \u00e9taient renseign\u00e9es localement grace \u00e0 un fichier de propri\u00e9t\u00e9s.<br \/>\nL&rsquo;inconv\u00e9nient de cette approche est \u00e9vident lorsque vient le temps d&rsquo;y ajouter de nouvelles vid\u00e9os.<br \/>\nDans ce tutoriel, nous verrons comment utiliser une API RESTFull pour fournir des donn\u00e9es \u00e0 une application Xcode.<\/p>\n<h1><\/h1>\n<h1>\u00c9l\u00e9ments de contenu<\/h1>\n<ul>\n<li>Utiliser ad\u00e9quatement NSArray(fromURL:), Array et Dictionary.<\/li>\n<li>Programmer une API Web (en utilisant une approche\u00a0<span style=\"color: #545454;\">\u00a0<\/span><a style=\"color: #0b0080;\" title=\"RESTful\" href=\"http:\/\/fr.wikipedia.org\/w\/index.php?title=Representational_State_Transfer&amp;redirect=no\">RESTful<\/a>)<\/li>\n<li>Utiliser une API RESTful dans une application Xcode: \u00a0<a href=\"http:\/\/www.rottentomatoes.com\/\">www.rottentomatoes.com<\/a>.<\/li>\n<li>Programmer des traitements non bloquants pour une application.<\/li>\n<\/ul>\n<p>&nbsp;<br \/>\n<div id=\"attachment_260\" style=\"width: 219px\" class=\"wp-caption alignleft\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-260\" class=\" wp-image-260\" src=\"\/xcode\/wp-content\/uploads\/2013\/10\/tomato1.png\" alt=\"tomato1\" width=\"209\" height=\"219\" \/><p id=\"caption-attachment-260\" class=\"wp-caption-text\">voir note au bas<\/p><\/div><br \/>\n<strong>Pr\u00e9-requis:<\/strong><\/p>\n<ol>\n<li>Avoir compl\u00e9t\u00e9 le tutoriel\u00a0<a href=\"\/xcode\/index.php\/labo\/timflix-delegation-et-uitableview-personnalisee\/\">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>S&rsquo;inscrire sur le site de\u00a0<a href=\"http:\/\/developer.rottentomatoes.com\/member\/register\">rottentomatoes<\/a><\/li>\n<li>Obtenir une cl\u00e9\u00a0<a href=\"http:\/\/developer.rottentomatoes.com\/apps\/register\">d\u00e9veloppeur<\/a><\/li>\n<\/ol>\n<p>&nbsp;<br \/>\n&nbsp;<br \/>\n&nbsp;<br \/>\nVid\u00e9o du r\u00e9sultat final:<br \/>\n<iframe loading=\"lazy\" width=\"700\" height=\"394\" src=\"https:\/\/www.youtube.com\/embed\/LBi6Z0RnINM?feature=oembed\" frameborder=\"0\" allowfullscreen><\/iframe><br \/>\n&nbsp;<br \/>\n&nbsp;<\/p>\n<hr \/>\n<h1>API web d&rsquo;acc\u00e8s \u00e0 une base de donn\u00e9es<\/h1>\n<p>C&rsquo;est une \u00a0pratique courante que d&rsquo;offrir l&rsquo;acc\u00e8s \u00e0 des donn\u00e9es via des URLs web selon la m\u00e9thode\u00a0<a style=\"color: #0b0080;\" title=\"RESTful\" href=\"http:\/\/fr.wikipedia.org\/w\/index.php?title=Representational_State_Transfer&amp;redirect=no\">RESTful<\/a>.<br \/>\nL&rsquo;avantage de cette approche est qu&rsquo;il n&rsquo;est pas n\u00e9cessaire d&rsquo;offrir un acc\u00e8s direct au <span style=\"color: #003366;\"><strong>SGBD<\/strong><\/span> (syst\u00e8me de gestion de la base de donn\u00e9es) de l&rsquo;organisation.<br \/>\nPar exemple, via une connexion \u00e0 la BD par programmation, par utilisation d&rsquo;outils comme phpMyAdmin, Oracle connect ou, \u00a0des\u00a0connaissances techniques du SGBD.<br \/>\nLa technique, est d&rsquo;offrir des <span style=\"color: #003366;\"><strong><span style=\"text-decoration: underline;\">scripts de type &lsquo;serveur web&rsquo; de traitements<\/span><\/strong><\/span> et <span style=\"color: #003366;\"><strong><span style=\"text-decoration: underline;\">d&rsquo;acc\u00e8s \u00e0 la base de donn\u00e9es<\/span><\/strong><\/span>.<br \/>\nCes scripts, \u00e9crits en <span style=\"color: #003366;\"><strong>PHP<\/strong><\/span>, <span style=\"color: #003366;\"><strong>ASP<\/strong><\/span>, <span style=\"color: #003366;\"><strong>Python<\/strong><\/span>, &#8230;, \u00a0peuvent alors \u00eatre lanc\u00e9s \u00e0 partir d&rsquo;une simple requ\u00eate HTTP soit dans un fureteur ou soit dans une application: en utilisant des fonctions ou de objets tel que <span style=\"color: #003366;\"><strong>curl()<\/strong><\/span>, <span style=\"color: #003366;\"><strong>NSArray(URL:)<\/strong><\/span> et autres.<br \/>\nVoir la d\u00e9finition de <a href=\"http:\/\/fr.wikipedia.org\/w\/index.php?title=Representational_State_Transfer&amp;redirect=no\">Representational State Transfer<\/a>.<br \/>\nPour l&rsquo;interrogation des donn\u00e9es, le script peut retourner les donn\u00e9es dans un format ind\u00e9pendant du SGBD tel que;<br \/>\n<span style=\"color: #003366;\"><strong>Texte<\/strong>, <strong>XML<\/strong>, <strong>JSON<\/strong>, <strong>CSV et<\/strong>\u00a0<strong>PList.<\/strong><\/span><br \/>\nPar exemple, l&rsquo;URL suivante,<br \/>\n<span style=\"color: #003366;\"><strong>http:\/\/uneApi.org\/obtenir_liste_stages.php?region=mtl&amp;format=csv<\/strong><\/span><br \/>\nPourrait retourner la liste des lieux de stage pour\u00a0\u00a0la r\u00e9gion de Montr\u00e9al en format csv:<\/p>\n<blockquote><p>\u00ab\u00a0Ubisoft\u00a0\u00bb,\u00a0\u00bb2&Prime;,\u00a0\u00bbHiv15&Prime;<br \/>\n\u00ab\u00a0Gameloft\u00a0\u00bb,\u00a0\u00bb1&Prime;,\u00a0\u00bbHiv15&Prime;<\/p><\/blockquote>\n<p>&nbsp;<\/p>\n<hr \/>\n<h1>Programmer une API Web<\/h1>\n<p>Pour programmer une API Web d&rsquo;acc\u00e8s \u00e0 une base de donn\u00e9es il suffit d&rsquo;avoir acc\u00e8s \u00e0 un serveur Web (<span style=\"color: #003366;\"><strong>IIS, Apache, &#8230;<\/strong><\/span>), \u00e0 un langage script cot\u00e9 serveur (<span style=\"color: #003366;\"><strong>php, ASP, node.JS, &#8230;<\/strong><\/span>) et \u00e0 un\u00a0SGBD\u00a0(<span style=\"color: #003366;\"><strong>MySQL, MSSQL, Oracle, PostgreSQL, &#8230;<\/strong><\/span> ).<br \/>\nDans le cadre d&rsquo;apprentissages, une solution comme <a href=\"http:\/\/www.wampserver.com\"><strong>WAMP<\/strong><\/a>\u00a0est id\u00e9ale.<br \/>\n<strong>En pratique, voici comment\u00a0offrir un API Web\u00a0d&rsquo;interrogation d&rsquo;une table proposant des pens\u00e9es du jour:\u00a0<\/strong><br \/>\n<span style=\"color: #ff0000;\"><strong>API.TIM.01<\/strong><\/span> &#8211; \u00c0 partir d&rsquo;une table, &lsquo;penseesdujours&rsquo;:<br \/>\n<img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-2191\" src=\"\/xcode\/wp-content\/uploads\/2014\/09\/apitim_01.png\" alt=\"apitim_01\" width=\"913\" height=\"323\" \/><br \/>\n&nbsp;<br \/>\n<span style=\"color: #ff0000;\"><strong>API.TIM.02<\/strong><\/span>\u00a0&#8211; D&rsquo;un script PHP \u00e0 l&rsquo;adresse &lsquo;\/unScript.php&rsquo;<\/p>\n<pre class=\"lang:php decode:true \">\/\/ Requ\u00eate SQL pour obtenir les enregistrements de la table penseesdujours\n\/\/ Connexion \u00e0 la BD\nmysql_connect(\"localhost\", \"user\", \"password\")  or die(mysql_error());\nmysql_select_db(\"cours_xcode\") or die(mysql_error());\n\/\/ Ex\u00e9cuter un requ\u00eate SQL\n$res = mysql_query(\"SELECT `nom_ajout` ,  `created_at` ,  `adresse_ip` , `pensee_texte`,  `pensee_auteur`,  `pensee_lien_image` FROM penseesdujours\") or die(mysql_error());\n\/\/ Parcourir les \u00e9l\u00e9ments du tableau de r\u00e9sultats\nwhile($r = mysql_fetch_assoc($res)) {\n  $xx = array_map(\"utf8_encode\", $r);\n  foreach ($xx as $key =&gt; $value) {\n    echo \"cl\u00e9 = $key, valeur = $value\\n\";\n  } \/\/ foreach\n} \/\/ while encore un r\u00e9sultat\n<\/pre>\n<p>&nbsp;<br \/>\n<span style=\"color: #ff0000;\"><strong>API.TIM.03<\/strong><\/span>\u00a0&#8211; L&rsquo;API retournera, au client du lien, le texte suivant:<\/p>\n<blockquote><p>cl\u00e9 = nom_ajout, valeur = Alain<br \/>\ncl\u00e9 = created_at, valeur = 2014-11-01 06:11:47<br \/>\ncl\u00e9 = adresse_ip, valeur = 24.200.185.163<br \/>\ncl\u00e9 = pensee_texte, valeur = On ne re\u00e7oit pas la sagesse, il faut la d\u00e9couvrir soi-m\u00eame, apr\u00e8s un trajet que personne ne peut faire pour nous, ne peut nous \u00e9pargner.<br \/>\ncl\u00e9 = pensee_auteur, valeur = Marcel Proust<br \/>\ncl\u00e9 = pensee_lien_image, valeur = http:\/\/upload.wikimedia.org\/wikipedia\/commons\/thumb\/7\/7e\/Marcel_Proust_1900.jpg\/220px-Marcel_Proust_1900.jpg<br \/>\ncl\u00e9 = nom_ajout, valeur = Alain<br \/>\ncl\u00e9 = created_at, valeur = 2014-11-01 06:11:05<br \/>\ncl\u00e9 = adresse_ip, valeur = 24.200.185.163<br \/>\ncl\u00e9 = pensee_texte, valeur = Ce qui compte, chez un homme, ce n&rsquo;est pas la couleur de sa peau ou la texture de sa chevelure, mais la texture et la qualit\u00e9 de son \u00e2me.<br \/>\ncl\u00e9 = pensee_auteur, valeur = Martin Luther King<br \/>\ncl\u00e9 = pensee_lien_image, valeur = http:\/\/seattletimes.com\/art\/mlk\/index.jpg<\/p><\/blockquote>\n<p><a href=\"\/cours\/xcode\/api_tim\/public\/index.php\/requetes_api\/?type=liste_pensees&amp;mode=all&amp;format=texte\">\u00a0lien de test<\/a><br \/>\n&nbsp;<br \/>\n<span style=\"color: #ff0000;\"><strong>API.TIM.04<\/strong><\/span>\u00a0&#8211; Voici un script PHP de mise en format &lsquo;plist&rsquo; &#8211; voir la structure d&rsquo;un fichier &lsquo;plist&rsquo; sous Xcode:<\/p>\n<pre class=\"lang:swift decode:true \">echo '&lt;?xml version=\"1.0\" encoding=\"UTF-8\"?&gt;'.\"\\n\";\necho '&lt;!DOCTYPE plist PUBLIC \"-\/\/Apple\/\/DTD PLIST 1.0\/\/EN\" \"http:\/\/www.apple.com\/DTDs\/PropertyList-1.0.dtd\"&gt;'.\"\\n\";\necho '&lt;plist version=\"1.0\"&gt;'.\"\\n\";\necho \"&lt;!-- Liste g\u00e9n\u00e9r\u00e9e par l'API TIM le \".date('Y-m-d h:m:s').\" --&gt;\\n\";\necho \"&lt;!-- (c) 2014 par Alain Boudreault --&gt;\\n\";\necho \"&lt;array&gt;\\n\";\nwhile($r = mysql_fetch_assoc($res)) {\n  $xx = array_map(\"utf8_encode\", $r);\n  echo \"\\t&lt;dict&gt;\\n\";\n  foreach ($xx as $key =&gt; $value) {\n    echo \"\\t\\t&lt;key&gt;\".$key.\"&lt;\/key&gt;\\n\\t\\t&lt;string&gt;\".$value.\"&lt;\/string&gt;\\n\";\n  } \/\/ foreach\n  echo \"\\t&lt;\/dict&gt;\\n\";\n} \/\/ while\necho \"&lt;\/array&gt;\\n&lt;\/plist&gt;\";<\/pre>\n<p>&nbsp;<br \/>\n<span style=\"color: #ff0000;\"><strong>API.TIM.05<\/strong><\/span>\u00a0&#8211;\u00a0Produira le\u00a0r\u00e9sultat suivant:<\/p>\n<pre class=\"lang:xhtml decode:true\">&lt;?xml version=\"1.0\" encoding=\"UTF-8\"?&gt;\n&lt;!DOCTYPE plist PUBLIC \"-\/\/Apple\/\/DTD PLIST 1.0\/\/EN\" \"http:\/\/www.apple.com\/DTDs\/PropertyList-1.0.dtd\"&gt;\n&lt;plist version=\"1.0\"&gt;\n&lt;!-- Liste g\u00e9n\u00e9r\u00e9e par l'API TIM le 2014-11-02 09:11:55 --&gt;\n&lt;!-- (c) 2014 par Alain Boudreault --&gt;\n&lt;array&gt;\n\t&lt;dict&gt;\n\t\t&lt;key&gt;nom_ajout&lt;\/key&gt;\n\t\t&lt;string&gt;Alain&lt;\/string&gt;\n\t\t&lt;key&gt;created_at&lt;\/key&gt;\n\t\t&lt;string&gt;2014-11-01 06:11:47&lt;\/string&gt;\n\t\t&lt;key&gt;adresse_ip&lt;\/key&gt;\n\t\t&lt;string&gt;24.200.185.163&lt;\/string&gt;\n\t\t&lt;key&gt;pensee_texte&lt;\/key&gt;\n\t\t&lt;string&gt;On ne re\u00e7oit pas la sagesse, il faut la d\u00e9couvrir soi-m\u00eame, apr\u00e8s un trajet que personne ne peut faire pour nous, ne peut nous \u00e9pargner.&lt;\/string&gt;\n\t\t&lt;key&gt;pensee_auteur&lt;\/key&gt;\n\t\t&lt;string&gt;Marcel Proust&lt;\/string&gt;\n\t\t&lt;key&gt;pensee_lien_image&lt;\/key&gt;\n\t\t&lt;string&gt;http:\/\/upload.wikimedia.org\/wikipedia\/commons\/thumb\/7\/7e\/Marcel_Proust_1900.jpg\/220px-Marcel_Proust_1900.jpg&lt;\/string&gt;\n\t&lt;\/dict&gt;\n&lt;\/array&gt;\n&lt;\/plist&gt;\n<\/pre>\n<p><a href=\"\/cours\/xcode\/api_tim\/public\/index.php\/requetes_api\/?type=liste_pensees&amp;mode=rnd&amp;quant=2&amp;format=plist\">lien de test\u00a0<\/a><br \/>\n<span style=\"color: #ff0000;\"><strong>API.TIM.06<\/strong><\/span>\u00a0&#8211; Un script PHP de mise en format\u00a0&lsquo;<a href=\"http:\/\/fr.wikipedia.org\/wiki\/JavaScript_Object_Notation\">JSON<\/a>&lsquo;<\/p>\n<pre class=\"lang:swift decode:true\">\/\/ tableau du r\u00e9sultat final\n$resultat = array();\n$resultat['info'] = array(\"API_TIM\" =&gt; \"version 2014.10.01\", \"type_requete\" =&gt; Input::get('mode'));\nwhile($r = mysql_fetch_assoc($res)) {\n  \/\/ Encoder les caract\u00e8res accentu\u00e9s.\n  $tableauAvecAccents[] = array_map(\"utf8_encode\", $r);\n} \/\/ while\n$resultat['resultat'] = $tableauAvecAccents;\n\/\/ Convertir un tableau en format JSON\necho json_encode($resultat);<\/pre>\n<p>&nbsp;<br \/>\n<span style=\"color: #ff0000;\"><strong>API.TIM.07<\/strong><\/span>\u00a0&#8211;\u00a0Produira le\u00a0r\u00e9sultat suivant:<\/p>\n<pre class=\"lang:swift decode:true\">{\n  \"info\":{\"API_TIM\":\"version 2014.10.01\",\"type_requete\":\"rnd\"},\n  \"resultat\":[\n                { \"nom_ajout\":\"admin\",\n                  \"created_at\":\"2014-11-01 10:11:56\",\n                  \"adresse_ip\":\"24.200.185.163\",\n                  \"pensee_texte\":\"La qualit\\u00e9 d'un homme se calcule \\u00e0 sa d\\u00e9mesure ; tentez, essayez, \\u00e9chouez m\\u00eame, ce sera votre r\\u00e9ussite\\u0085\",\n                  \"pensee_auteur\":\"Jacques Brel\",\n                  \"pensee_lien_image\":\"https:\\\/\\\/encrypted-tbn2.gstatic.com\\\/images?q=tbn:ANd9GcQqWOL6fBMrhIECWoOuY3aEdxrm6biaZTdi5Kp72TC_xG9L11GS\"\n                },\n                ...\n             ]\n}<\/pre>\n<p><a href=\"\/cours\/xcode\/api_tim\/public\/index.php\/requetes_api\/?type=liste_pensees&amp;mode=rnd&amp;quant=2\">lien de test<\/a><br \/>\n<a href=\"\/cours\/xcode\/api_tim\/public\/index.php\/user\/langue?lang=fr\">Lien vers l&rsquo;API TIM\u00a0<\/a>\u00a0(utilisateur: \u00e9tudiant:tim)<br \/>\nExemple complet (Laravel)<\/p>\n<pre class=\"lang:swift decode:true\">&lt;?php\n\/*\n\t--------------------------------------------------------------\n\tProjet:\n\tClasse:\t\t\trequetes.php\n\tAuteur:\t\t\tAlain Boudreault\n\tDate:\t\t\t2015.02.10\n\t--------------------------------------------------------------\n\tDescription:\n\t--------------------------------------------------------------\n\tEntr\u00e9e:\n\tSortie:\n\t--------------------------------------------------------------\n\tM-A-J:\n\t--------------------------------------------------------------\n*\/\nclass Requetes_api_Controller extends Base_Controller {\n\tfunction __construct()\n\t{\n\t\tparent::__construct();\n\t}\n\tpublic function action_index()\n\t{\n\t$user =  is_null(Auth::user())?'':Auth::user()-&gt;username;\n\tif (Input::get('type') == 'liste_pensees')\t{\n\t$mode  = Input::get('mode');\n\t$quant = Input::get('quant');\n\t\tTrace::ajouter($user,'API','Requ\u00eate: Liste des pens\u00e9es', 0);\n\t\treturn View::make('requetes.apiweb')\n\t\t\t-&gt;with('quant', $quant)\n\t\t\t-&gt;with('mode', $mode)\n\t\t\t-&gt;with('format', Input::get('format'));\n\t\t} \/\/ if config\n\t}\n}\n<\/pre>\n<pre class=\"lang:swift decode:true \">@layout('vide')\n@section('content')\n&lt;?php\n\/\/ Fichier: apiweb.blade.php\n\/\/ Auteur:  Alain Boudreault\n\/\/ Requ\u00eate SQL pour obtenir les enregistrements de la table penseesdujours\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tmysql_connect(\"localhost\", \"aboudrea\", \"lnAvril67\")  or die(mysql_error());\nmysql_select_db(\"cours_xcode\") or die(mysql_error());\n$rows = array();\t\t\t\/\/ R\u00e9sultat final\n$rows['info'] = array(\"API_TIM\" =&gt; \"version 2014.10.01\", \"type_requete\" =&gt; Input::get('mode'));\nif (Input::get('mode') == 'all')\t{\n\t$res = mysql_query(\"SELECT `nom_ajout` ,  `created_at` ,  `adresse_ip` , `pensee_texte`,  `pensee_auteur`,  `pensee_lien_image` FROM penseesdujours\") or die(mysql_error());\n}  \/\/ mode=all\nif (Input::get('mode') == 'rnd')\t{\n\t$quant = Input::get('quant');\n\t$res = mysql_query(\"SELECT `nom_ajout` ,  `created_at` ,  `adresse_ip` , `pensee_texte`,  `pensee_auteur`,  `pensee_lien_image` FROM penseesdujours ORDER BY RAND() LIMIT $quant\") or die(mysql_error());\n} \/\/ mode=rnd\nif (Input::get('mode') == 'adulte')\t{\n\t$quant = Input::get('quant');\n\t$res = mysql_query(\"SELECT * FROM (SELECT `nom_ajout` ,  `created_at` ,  `adresse_ip` , `pensee_texte`,  `pensee_auteur`,  `pensee_lien_image` FROM penseesdujours where categorie = 3) as tmp ORDER BY RAND() LIMIT $quant\") or die(mysql_error());\n} \/\/ mode=adulte\n\/\/ Lecture des pensees du jour\nif(!$res) {\n\techo \"Error: no results from table devices\";\n        die(json_encode(array(\"error\" =&gt; \"no results from table\")));\n    }\n\/\/ Parcourir les \u00e9l\u00e9ments du tableau de r\u00e9sultats\nif (Input::get('format') == 'texte')\n{\n\twhile($r = mysql_fetch_assoc($res))\n\t{\n  \t$xx = array_map(\"utf8_encode\", $r);\n  \tforeach ($xx as $key =&gt; $value)\n\t\t{\n    \techo \"cl\u00e9 = $key, valeur = $value&lt;br \/&gt;\\n\";\n  \t}\n\t} \/\/ while\n} \/\/ format=texte\nelse {\nif (Input::get('format') == 'plist')\t{\n\techo '&lt;?xml version=\"1.0\" encoding=\"UTF-8\"?&gt;'.\"\\n\";\n\techo '&lt;!DOCTYPE plist PUBLIC \"-\/\/Apple\/\/DTD PLIST 1.0\/\/EN\" \"http:\/\/www.apple.com\/DTDs\/PropertyList-1.0.dtd\"&gt;'.\"\\n\";\n\techo '&lt;plist version=\"1.0\"&gt;'.\"\\n\";\n\techo \"&lt;array&gt;\\n\";\n\t  while($r = mysql_fetch_assoc($res)) {\n\t\t\t\t\t\t$xx = array_map(\"utf8_encode\", $r);\n\t\t\t\t\t\techo \"\\t&lt;dict&gt;\\n\";\n\t\t\t\t\t\tforeach ($xx as $key =&gt; $value) {\n\t\t\t\t\t\t\t\techo \"\\t\\t&lt;key&gt;\".$key.\"&lt;\/key&gt;\\n\\t\\t&lt;string&gt;\".$value.\"&lt;\/string&gt;\\n\";\n\t\t\t\t\t\t}\n\t\t\t\t\t\techo \"\\t&lt;\/dict&gt;\\n\";\n\t\t\t}\n  echo \"&lt;\/array&gt;\\n&lt;\/plist&gt;\";\n}\nelse  \/\/ format json\n{\n\twhile($r = mysql_fetch_assoc($res)) {\n\t\t\t$sous_ensemble[] = array_map(\"utf8_encode\", $r);\n\t\t}\n\t\t$rows['resultat'] = $sous_ensemble;\n\t\techo json_encode($rows);\n}\n}\n?&gt;\n@endsection<\/pre>\n<p>&nbsp;<\/p>\n<hr \/>\n<h1>Retour sur les tableaux et les optionnelles<\/h1>\n<p><span style=\"color: #ff0000;\">Dans un nouveau projet,\u00a0<\/span><br \/>\n<span style=\"color: #ff0000;\"><strong>Action tableau.01<\/strong><\/span> &#8211; \u00a0Cr\u00e9er un\u00a0Array&lt;Dictionary&lt;String, String&gt;&gt; \u00e0 partir d&rsquo;une URL via NSArray():<\/p>\n<pre class=\"lang:swift decode:true\">func testerTableau01() {\n    \/\/ Cr\u00e9ation d'un Array&lt;Dictionary&lt;String, String&gt;&gt; \u00e0 partir d'une URL\n    let urlAPI = \"\/cours\/xcode\/api_tim\/public\/index.php\/requetes_api\/?type=liste_pensees&amp;mode=all&amp;format=plist\"\n    let tableauDonnees = NSArray(contentsOfURL: NSURL(string: urlAPI)!) as! Array&lt;Dictionary&lt;String, String&gt;&gt;\n    if  tableauDonnees.count == 0 {\n        println(\"Pas de tableau!\")\n    } else {\n        println(tableauDonnees)\n    }  \/\/ if tableauDonnees\n} \/\/ testerTableau01()\ntesterTableau01()<\/pre>\n<p>&nbsp;<br \/>\n<span style=\"color: #ff0000;\"><strong>Action tableau.02<\/strong><\/span>\u00a0&#8211; \u00a0Utiliser des types &lsquo;Foundation (NS)&rsquo;, pour acc\u00e9der aux \u00e9l\u00e9ments du tableau:<br \/>\n<strong><span style=\"color: #ff0000;\">Note<\/span><\/strong>: \u00c0 ajouter dans la section \u00ab\u00a0else {}\u00a0\u00bb.<\/p>\n<pre class=\"lang:swift decode:true\">       \/\/ Note: Obtenir et afficher un des \u00e9l\u00e9ments du tableau.\n        let w = tableauDonnees[4]\n        println(w)\n        let unePensee = w[\"pensee_texte\"]!\n        println(unePensee)\n        for x in tableauDonnees {\n            var texte = \"----------------------------------\\n\"\n            let auteur = x[\"pensee_auteur\"]!\n            let pensee = x[\"pensee_texte\"]!\n            texte += \"L'auteur \\(auteur) a dit:\\n\\(pensee)\"\n            println(texte)\n        } \/\/ for x in tableau<\/pre>\n<p>&nbsp;<br \/>\n<span style=\"color: #ff0000;\"><strong>Action tableau.03<\/strong><\/span>\u00a0&#8211; \u00a0Cr\u00e9er une optionnelle de type \u00a0Array \u00e0 partir d&rsquo;une URL:<\/p>\n<pre class=\"lang:swift decode:true\">let tableauDonnees = NSArray(contentsOfURL: NSURL(string: \"\/cours\/xcode\/api_tim\/public\/index.php\/requetes_api\/?type=liste_pensees&amp;mode=all&amp;format=plist\")!) as Array?\nif tableauDonnees == nil {\n    println(\"Pas de tableau!\")\n} else {\n    println(tableauDonnees)\n}  \/\/ if tableauDonnees<\/pre>\n<p>&nbsp;<br \/>\n<span style=\"color: #ff0000;\"><strong>Action tableau.04<\/strong><\/span>\u00a0&#8211; \u00a0Utiliser des optionnelles\u00a0pour acc\u00e9der aux \u00e9l\u00e9ments du tableau:<\/p>\n<pre class=\"lang:swift decode:true\"> for x in tableauDonnees {\n    println(\"\\n----------------------------------\")\n    if let y = x[\"pensee_auteur\"] as? String{\n        println(\"L'auteur \\(y) a dit:\\n\")\n    }\n    if let y = x[\"pensee_text\"] as? String{\n        println(y)\n    }\n} \/\/ for x in tableau<\/pre>\n<p><span style=\"color: #000000;\">[expand title=\u00a0\u00bbAfficher la solution\u00a0\u00bb]<\/span><\/p>\n<ul>\n<li>D\u00e9baller le tableau car il est optionnel -&gt; for x in tableauDonnees!<\/li>\n<li>Corriger la cl\u00e9 \u00ab\u00a0pense_text\u00a0\u00bb -&gt; \u00ab\u00a0pensee_texte\u00a0\u00bb<\/li>\n<\/ul>\n<p><span style=\"color: #000000;\">[\/expand]<\/span><br \/>\n&nbsp;<br \/>\n<strong><span style=\"color: #ff0000;\">Note:\u00a0<\/span><span style=\"color: #000000;\">Il faut\u00a0utiliser &lsquo;?&rsquo; pour le\u00a0typage d&rsquo;une affectation optionnelle: as? String. \u00a0<\/span><\/strong><br \/>\n&nbsp;<br \/>\n<span style=\"color: #ff0000;\"><strong>Action tableau.05<\/strong><\/span>\u00a0&#8211; Modifiez le code pr\u00e9c\u00e9dent pour afficher une trace lorsqu&rsquo;une des cl\u00e9s du tableau est invalide.<br \/>\n&nbsp;<br \/>\n<span style=\"color: #ff0000;\"><strong>Action tableau.06<\/strong><\/span>\u00a0&#8211; D\u00e9finition\u00a0d&rsquo;un tableau complexe:<\/p>\n<pre class=\"lang:swift decode:true\">        var tableauComplexe:Dictionary&lt;String, AnyObject&gt;?\n        tableauComplexe = [ \"nom\":\"Bob\",\n                            \"amis\": [\n                                        [\"nom\":\"ami01\", \"email\":\"x@y.com\"],\n                                        [\"nom\":\"ami02\", \"email\":\"a@b.com\"]\n                                     ]\n                            ,\n                            \"pointage\": [2,45,56]\n                         ]\n        println(tableauComplexe)<\/pre>\n<p><strong>R\u00e9sultat:<\/strong><\/p>\n<pre class=\"lang:swift decode:true \">Optional([\"nom\": Bob, \"pointage\": &lt;_TtCSs23_ContiguousArrayStorage00007FB951786DA0 0x7fb951787d10&gt;(\n2,\n45,\n56\n)\n, \"amis\": &lt;_TtCSs23_ContiguousArrayStorage00007FB951785B80 0x7fb951785140&gt;(\n{\n    email = \"x@y.com\";\n    nom = ami01;\n},\n{\n    email = \"a@b.com\";\n    nom = ami02;\n}\n)\n])<\/pre>\n<p><strong style=\"color: #ff0000;\">\u00a0Note importante:<\/strong><span style=\"color: #ff0000;\">\u00a0<\/span><span style=\"color: #000000;\">Lorsqu&rsquo;un Dictionary contient des\u00a0\u00e9l\u00e9ments complexes de type AnyObject, les \u00e9l\u00e9ments doivent alors \u00eatre typ\u00e9s vers des classes de type NSObject.<\/span><br \/>\n<span style=\"color: #000000;\">\u00a0<\/span><br \/>\n<span style=\"color: #ff0000;\"><strong>Action tableau.06.01<\/strong><\/span>\u00a0&#8211; Acc\u00e8s\u00a0aux \u00e9l\u00e9ments d&rsquo;un tableau complexe:<\/p>\n<pre class=\"lang:swift decode:true\">\/\/ Trouver les erreurs!\nlet lesAmisDeBob = tableauComplexe[\"amis\"]\nprintln(lesAmisDeBob)<\/pre>\n<p><span style=\"color: #000000;\">[expand title=\u00a0\u00bbAfficher la solution\u00a0\u00bb]<\/span><\/p>\n<ul>\n<li><span style=\"color: #000000;\">Il faut d\u00e9baller le tableau car il est optionnel: tableauComplexe!<\/span><\/li>\n<li>Il faut typer le r\u00e9sultat: \u00a0as! Array&lt;Dictionary&lt;String, String&gt;&gt;[\/expand]<\/li>\n<\/ul>\n<p><strong><span style=\"color: #000000;\">R\u00e9sultat:<\/span><\/strong><\/p>\n<pre class=\"lang:swift decode:true \">Optional(&lt;_TtCSs23_ContiguousArrayStorage00007FBC1AE13F40 0x7fbc1ae134d0&gt;(\n{\n    email = \"x@y.com\";\n    nom = ami01;\n},\n{\n    email = \"a@b.com\";\n    nom = ami02;\n}\n)\n)<\/pre>\n<p>Note: \u00a0Il est pr\u00e9f\u00e9rable de typer la d\u00e9claration,<br \/>\n<img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-2237\" src=\"\/xcode\/wp-content\/uploads\/2014\/09\/retour.tableau.01.png\" alt=\"retour.tableau.01\" width=\"1177\" height=\"64\" \/><br \/>\ncar il ne sera pas possible de faire:<br \/>\nprintln(lesAmisDeBob[<span style=\"color: #0435ff;\">0<\/span>])<br \/>\nPr\u00e9sentement, lesAmisDeBob est de type AnyObject.<br \/>\n<strong>La solution:<\/strong><\/p>\n<pre class=\"lang:swift decode:true\">\/\/ Note: un Anyobject doit \u00eatre typ\u00e9 vers une classe de type NSObject.\nlet lesAmisDeBob = tableauComplexe![\"amis\"] as! Array&lt;Dictionary&lt;String, String&gt;&gt;\nprintln(lesAmisDeBob[0])<\/pre>\n<p>&nbsp;<br \/>\n<span style=\"color: #ff0000;\"><strong>Action tableau.06.02<\/strong><\/span>\u00a0&#8211; Cr\u00e9ez un tableau &lsquo;lesAmisDeBob&rsquo; en utilisant une d\u00e9claration conditionnelle. \u00a0Note: aucun d\u00e9ballage.<br \/>\n<span style=\"color: #000000;\">[expand title=\u00a0\u00bbAfficher la solution\u00a0\u00bb]<\/span><\/p>\n<pre class=\"lang:swift decode:true\">        let INDICE_TABLEAU_AMIS = \"amis\"\n        if let tableauDeballe = tableauComplexe  {\n            let lesAmisdeBob = tableauDeballe[INDICE_TABLEAU_AMIS] as! Array&lt;Dictionary&lt;String, String&gt;&gt;\n        }<\/pre>\n<p><span style=\"color: #000000;\">[\/expand]<\/span><br \/>\n&nbsp;<br \/>\n<span style=\"color: #ff0000;\"><strong>Action tableau.06.03<\/strong><\/span>\u00a0&#8211;\u00a0Afficher la liste des amis<\/p>\n<pre class=\"lang:swift decode:true\">let INDICE_TABLEAU_AMIS = \"amis\"\nlet CHAMP_NOM = \"nomm\"\nif let tableauDeballe = tableauComplexe  {\n    println(tableauDeballe[INDICE_TABLEAU_AMIS])\n    if let lesAmisDeBob = tableauDeballe[INDICE_TABLEAU_AMIS] as? Array&lt;Dictionary&lt;String, String&gt;&gt;\n    {\n        println(\"Liste des amis de Bob\\n\\n\")\n        for ami in lesAmisDeBob {\n            if let nom = ami[CHAMP_NOM] {\n                println(nom)\n            }\n            else {\n                println(\"Erreur sur champ : \\(CHAMP_NOM)\")\n            }\n        } \/\/ for ami in\n    } \/\/ if let lesAmisdeBob\n} \/\/ let tableauDeballe = tableauComplexe<\/pre>\n<p>&nbsp;<br \/>\n<span style=\"color: #ff0000;\"><strong>Action tableau.06.04<\/strong><\/span>\u00a0&#8211; Afficher (sans utiliser des optionnelles dans le println()) le contenu du tableau des pointages.<br \/>\n&nbsp;<\/p>\n<hr \/>\n<h1>Programmer un app avec\u00a0l&rsquo;API TIM<\/h1>\n<p>&nbsp;<br \/>\n<span style=\"color: #ff0000;\"><strong>Action<\/strong><\/span> <span style=\"color: #ff0000;\"><strong>API.TIM.01<\/strong><\/span>\u00a0&#8211; Dans un nouveau projet, ajoutons le code suivant:<\/p>\n<pre class=\"lang:swift decode:true\">\/\/  ViewController.swift\nimport UIKit\nclass ViewController: UIViewController {\n    \/\/ Dans le cas d'un tableau cr\u00e9\u00e9 \u00e0 partir d'une plist obtenu via une URL, il est plus simple\n    \/\/ de travailler avec les classes NS: NSString, NSNumber, NSArray, NSDictionary.\n    \/\/ Nous ferons moins de d\u00e9ballage.\n    \/\/ De plus, le type AnyObject doit \u00eatre typ\u00e9 vers un NS.\n    var tableauDonnees:NSArray?   \/\/ [Dictionary&lt;String, AnyObject&gt;]?\n    override func viewDidLoad() {\n        super.viewDidLoad()\n        let tableauDonnees = NSArray(contentsOfURL: NSURL(string: \"\/cours\/xcode\/api_tim\/public\/index.php\/requetes_api\/?type=liste_pensees&amp;mode=all&amp;format=plist\")!) as! Array&lt;Dictionary&lt;String, String&gt;&gt;\n        \/\/ println(tableauDonnees)\n        \/\/ Note: Obtenir et afficher un des \u00e9l\u00e9ments du tableau.\n        let w = tableauDonnees[4]\n        println(w)\n        let unePensee = w[\"pensee_texte\"]!\n        println(unePensee)\n        \/*\n        \/\/ Commentaire \u00e0 enlever \u00e0 la prochaine \u00e9tape.\n        \/\/ Afficher tous les \u00e9l\u00e9ments de tableauDonnees.\n        \/\/ Note: pas de boucle si tableau est nil.\n        for x in tableauDonnees {\n        println(\"\\n----------------------------------\")\n        if let y = x[\"pensee_auteur\"]{\n            println(\"L'auteur \\(y) a dit:\\n\")\n        }\n        if let y = x[\"pensee_texte\"]{\n            println(y)\n        }\n        } \/\/ for x in tableau\n        \/\/ ****** Commentaire \u00e0 enlever \u00e0 la prochaine \u00e9tape.\n        *\/\n    } \/\/ viewDidLoad()\n}  \/\/ ViewController<\/pre>\n<p><strong>R\u00e9sultat obtenu:<\/strong><\/p>\n<pre class=\"lang:swift decode:true\">\/\/ println(w)\n{\n    \"adresse_ip\" = \"24.200.185.163\";\n    \"created_at\" = \"2014-11-01 06:11:28\";\n    \"nom_ajout\" = Alain;\n    \"pensee_auteur\" = \"Jacques Chardonne\";\n    \"pensee_lien_image\" = \"http:\/\/www.albin-michel.fr\/multimedia\/Article\/Image\/2000\/9782226115287-X.jpg\";\n    \"pensee_texte\" = \"Poursuivre le bonheur, au lieu de le laisser venir, n'est-ce pas courir apr\\U00e8s le reflet d'un mot ? En fait, les hommes seraient plus heureux si on leur parlait moins de bonheur !\";\n}\n\/\/ Println(unePensee)\nPoursuivre le bonheur, au lieu de le laisser venir, n'est-ce pas courir apr\u00e8s le reflet d'un mot ? En fait, les hommes seraient plus heureux si on leur parlait moins de bonheur !\n<\/pre>\n<p>&nbsp;<\/p>\n<h3>Boucler sur les \u00e9l\u00e9ments du tableau. \u00a0Note: le tableau &lsquo;NSArray&rsquo; contient des \u00e9l\u00e9ments de type &lsquo;NSDictionary&rsquo;.<\/h3>\n<p><span style=\"color: #ff0000;\"><strong>Action API.TIM.02<\/strong><\/span>\u00a0&#8211;\u00a0\u00a0Effa\u00e7ons le commentaire de l&rsquo;exemple pr\u00e9c\u00e9dent:<br \/>\n<strong>R\u00e9sultat obtenu:<\/strong><\/p>\n<pre class=\"lang:swift decode:true\">----------------------------------\nL'auteur Marcel Proust a dit:\nOn ne re\u00e7oit pas la sagesse, il faut la d\u00e9couvrir soi-m\u00eame, apr\u00e8s un trajet que personne ne peut faire pour nous, ne peut nous \u00e9pargner.\n----------------------------------\nL'auteur Martin Luther King a dit:\nCe qui compte, chez un homme, ce n'est pas la couleur de sa peau ou la texture de sa chevelure, mais la texture et la qualit\u00e9 de son \u00e2me.\n...<\/pre>\n<p>&nbsp;<\/p>\n<h3>Cr\u00e9er un tableau \u00e0 partir d&rsquo;une structure JSON<\/h3>\n<p><span style=\"color: #ff0000;\"><strong>Action API.TIM.03<\/strong><\/span>\u00a0&#8211; \u00a0Observons la structure des donn\u00e9es retourn\u00e9e par le lien suivant:<br \/>\n<a href=\"\/cours\/xcode\/api_tim\/public\/index.php\/requetes_api\/?type=liste_pensees&amp;mode=rnd&amp;quant=5\">\/cours\/xcode\/api_tim\/public\/index.php\/requetes_api\/?type=liste_pensees&amp;mode=rnd&amp;quant=5<\/a><br \/>\nStructure des donn\u00e9es:<\/p>\n<pre class=\"lang:swift decode:true \">{\n  \"info\":{\"API_TIM\":\"version 2014.10.01\",\"type_requete\":\"rnd\"},\n  \"resultat\":[\n                { \"nom_ajout\":\"admin\",\n                  \"created_at\":\"2014-11-01 10:11:56\",\n                  \"adresse_ip\":\"24.200.185.163\",\n                  \"pensee_texte\":\"La qualit\\u00e9 d'un homme se calcule \\u00e0 sa d\\u00e9mesure ; tentez, essayez, \\u00e9chouez m\\u00eame, ce sera votre r\\u00e9ussite\\u0085\",\n                  \"pensee_auteur\":\"Jacques Brel\",\n                  \"pensee_lien_image\":\"https:\\\/\\\/encrypted-tbn2.gstatic.com\\\/images?q=tbn:ANd9GcQqWOL6fBMrhIECWoOuY3aEdxrm6biaZTdi5Kp72TC_xG9L11GS\"\n                },\n                ...\n             ]\n}<\/pre>\n<p>Nous avons affaire ici \u00e0 un dictionnaire de deux \u00e9l\u00e9ments:<\/p>\n<ul>\n<li>le champ &lsquo;info&rsquo; et<\/li>\n<li>le champ \u00a0&lsquo;resultat&rsquo;.<\/li>\n<\/ul>\n<p>Le champ &lsquo;info&rsquo; est un dictionnaire.<br \/>\nLe champ &lsquo;r\u00e9sultat&rsquo; est un tableau de dictionnaires.<br \/>\nVoici comment cr\u00e9er un <strong>NSDictionary<\/strong> \u00e0 partir d&rsquo;une telle structure:<br \/>\n<span style=\"color: #ff0000;\"><strong>Action API.TIM.04<\/strong><\/span>\u00a0&#8211; Ajoutons le code suivant:<\/p>\n<pre class=\"lang:swift decode:true\">        \/\/ Voici comment cr\u00e9er un dictionnaire \u00e0 partir d'un r\u00e9sultat JSON.\n        \/\/ ATTENTION, il n'y a aucune validation dans les lignes qui suivent.\n        \/\/ 1 - Cr\u00e9er une instance NSURL \u00e0 partir d'un lien\n        let adresseURL = \"\/cours\/xcode\/api_tim\/public\/index.php\/requetes_api\/?type=liste_pensees&amp;mode=rnd&amp;quant=5\"\n        let url = NSURL(string: adresseURL)\n        \/\/ 2 - Obtenir les donn\u00e9es (en format brut 'NSData': des octets sans signature)\n        let data = NSData(contentsOfURL:url!, options: nil, error: nil)\n        println(data)<\/pre>\n<p>&nbsp;<br \/>\n<strong>R\u00e9sultat obtenu:<\/strong><\/p>\n<pre class=\"lang:swift decode:true\">&lt;7b22696e 666f223a 7b224150 495f5449 4d223a22 76657273 696f6e20 32303134\n ...\n5c2f4c61 66657272 69657265 2d44616e 792d7765 622e6a70 67227d5d 7d0d0a&gt;\n<\/pre>\n<p>Tester avec :\u00a0<span style=\"color: #ff0000;\">http:\/\/finance.yahoo.com\/webservice\/v1\/symbols\/allcurrencies\/quote?format=json<\/span><br \/>\net: \u00a0<span style=\"color: #ff0000;\">\/xcode\/wp-content\/uploads\/2013\/10\/tomato1.png<\/span><br \/>\n<span style=\"color: #ff0000;\"><strong>Action API.TIM.05<\/strong><\/span>\u00a0&#8211; Ajoutons le code suivant:<\/p>\n<pre class=\"lang:swift decode:true\">        \/\/ 3 - Convertir les donn\u00e9es, du format JSON, vers un Dictionary &lt;String, AnyObject&gt;\n        let resultat = NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.MutableContainers, error: nil) as! Dictionary&lt;String, AnyObject&gt;\n        println(resultat)<\/pre>\n<p>&nbsp;<br \/>\n<strong>R\u00e9sultat obtenu:<\/strong><\/p>\n<pre class=\"lang:swift decode:true \">{\n    info =     {\n        \"API_TIM\" = \"version 2014.10.01\";\n        \"type_requete\" = rnd;\n    };\n    resultat =     (\n                {\n            \"adresse_ip\" = \"24.200.185.163\";\n            \"created_at\" = \"2014-11-01 06:11:38\";\n            \"nom_ajout\" = Alain;\n            \"pensee_auteur\" = \"F\\U00e9lix Leclerc\";\n            \"pensee_lien_image\" = \"https:\/\/lh3.googleusercontent.com\/Slux6I1NENJmWrdQvLEGQkHgZOuw9G8Fln1ZGR-qTzEzHnoYaO4wHo5cNn7EiY0Q3fwBbAuq-Vszcqc8b-oxzQHgDRFsdkV7V75stzUNP3dfUUQvjBsULifh2g\";\n            \"pensee_texte\" = \"Le mariage, c'est deux billets d'avion aller seulement, vers une \\U00eele inconnue. On en revient \\U00e0 la nage ou jamais.\";\n        },\n                {\n            \"adresse_ip\" = \"24.200.185.163\";\n            \"created_at\" = \"2014-11-01 10:11:56\";\n            \"nom_ajout\" = admin;\n            \"pensee_auteur\" = \"Jacques Brel\";\n            \"pensee_lien_image\" = \"https:\/\/encrypted-tbn2.gstatic.com\/images?q=tbn:ANd9GcQqWOL6fBMrhIECWoOuY3aEdxrm6biaZTdi5Kp72TC_xG9L11GS\";\n            \"pensee_texte\" = \"La qualit\\U00e9 d'un homme se calcule \\U00e0 sa d\\U00e9mesure ; tentez, essayez, \\U00e9chouez m\\U00eame, ce sera votre r\\U00e9ussite\\U0085\";\n        },\n                {\n            \"adresse_ip\" = \"24.200.185.163\";\n            \"created_at\" = \"2014-11-01 05:11:18\";\n            \"nom_ajout\" = Alain;\n            \"pensee_auteur\" = Him;\n            \"pensee_lien_image\" = \"http:\/\/cdn1.yourstory.com\/wp-content\/uploads\/2014\/04\/Image-1.jpg\";\n            \"pensee_texte\" = \"It's the story of a guy...\";\n        },\n                {\n            \"adresse_ip\" = \"24.200.185.163\";\n            \"created_at\" = \"2014-11-01 06:11:53\";\n            \"nom_ajout\" = Alain;\n            \"pensee_auteur\" = \"Dany Laferri\\U00e8re\";\n            \"pensee_lien_image\" = \"http:\/\/ifoa.org\/ifoa\/uploads\/2011\/07\/Laferriere-Dany-web.jpg\";\n            \"pensee_texte\" = \"On ne meurt pas tant qu\\U0092on bouge. Mais ceux qui n\\U0092ont jamais franchi la barri\\U00e8re de leur village attendent le retour du voyageur pour estimer si cela valait la peine de partir.\";\n        },\n                {\n            \"adresse_ip\" = \"24.200.185.163\";\n            \"created_at\" = \"2014-11-01 06:11:28\";\n            \"nom_ajout\" = Alain;\n            \"pensee_auteur\" = \"Jacques Chardonne\";\n            \"pensee_lien_image\" = \"http:\/\/www.albin-michel.fr\/multimedia\/Article\/Image\/2000\/9782226115287-X.jpg\";\n            \"pensee_texte\" = \"Poursuivre le bonheur, au lieu de le laisser venir, n'est-ce pas courir apr\\U00e8s le reflet d'un mot ? En fait, les hommes seraient plus heureux si on leur parlait moins de bonheur !\";\n        }\n    );\n}<\/pre>\n<p>&nbsp;<br \/>\nVoici un exemple d&rsquo;acc\u00e8s au dictionnaire obtenu:<br \/>\nNote: Dans le but de simplifier l&rsquo;apprentissage, l&rsquo;API TIM ne retourne que des contenus\u00a0de type chaine.<br \/>\n<span style=\"color: #ff0000;\"><strong><br \/>\nAction API.TIM.06<\/strong><\/span>\u00a0&#8211; Ajoutons le code suivant:<\/p>\n<pre class=\"lang:swift decode:true\">        \/\/ Obtenir l'\u00e9l\u00e9ment \u00e0 la cl\u00e9 \"resultat\":\n        let lesPensees = resultat[\"resultat\"] as! Array&lt;Dictionary&lt;String, String&gt;&gt;\n        println(lesPensees)\n        \/\/ Obtenir un \u00e9l\u00e9ment du tableau lesPensees:\n        let unePensee = lesPensees[3]\n        println(unePensee)\n        \/\/ Obtenir un des champs d'un \u00e9l\u00e9ment du tableau lesPensees:\n        let textePensee = lesPensees[3][\"pensee_texte\"]!\n        println(textePensee)<\/pre>\n<p>&nbsp;<br \/>\nAvec une syntaxe sans passer par des structures interm\u00e9diaires\u00a0. Par exemple,\u00a0 \u00a0let lesPensees = (resultat[\u00ab\u00a0resultat\u00a0\u00bb]) as [Dictionary&lt;String, String&gt;]<br \/>\n<span style=\"color: #ff0000;\"><strong>Action API.TIM.07<\/strong><\/span>\u00a0&#8211; Testons\u00a0le code suivant:<\/p>\n<pre class=\"lang:swift decode:true\">       let unAuteur = (((((resultat[\"resultat\"]) as! Array)[3]) as Dictionary)[\"pensee_auteur\"])! as String\n        println(unAuteur)\n<\/pre>\n<p>&#8211;&gt; Voir &lsquo;<strong>Simplifier l\u2019utilisation de JSON<\/strong>&lsquo; au bas du document<br \/>\n&nbsp;<br \/>\nVoici un exemple qui applique des principes de base de validation:<br \/>\n<span style=\"color: #ff0000;\"><strong>Action API.TIM.08<\/strong><\/span>\u00a0&#8211;\u00a0Validons l&rsquo;URL<\/p>\n<pre class=\"lang:swift decode:true\">\/\/        \/\/ Obtenir des \u00e9l\u00e9ments du tableau avec validation des nils:\n\/\/\n        var penseeValidee = Dictionary&lt;String, String&gt;()\n        var erreur:NSError?\n        let adresseURL = \"htt:\/\/tim.cstj.qc.ca\/cours\/xcode\/api_tim\/public\/index.php\/requetes_api\/?type=liste_pensees&amp;mode=rnd&amp;quant=5\"\n        let url = NSURL(string: adresseURL)\n        if let data = NSData(contentsOfURL:url!, options: nil, error: &amp;erreur){\n            \/\/ Ici, nous avons obtenu des donn\u00e9es vie une URL\n            penseeValidee[\"donneesViaURL\"] = \"R\u00e9ussit\"\n            \/\/if let resultat = NSJSONSerialization.JSONObjectWithData(data\n        } else \/\/ Erreur: URL invalide\n        {\n            penseeValidee[\"donneesViaURL\"] = \"Erreur de lecture des donn\u00e9es: \\(erreur)\"\n        } \/\/ else = Erreur: URL\n        println(penseeValidee)<\/pre>\n<p>&nbsp;<br \/>\n<span style=\"color: #ff0000;\"><strong>Action API.TIM.09<\/strong><\/span>\u00a0&#8211;\u00a0Testons (il y aura une erreur)<\/p>\n<pre class=\"lang:swift decode:true\">\/\/ [donneesViaURL: Erreur de lecture des donn\u00e9es: Optional(Error Domain=NSCocoaErrorDomain Code=256 \"The operation couldn\u2019t be completed. (Cocoa error 256.)\" UserInfo=0x7f8d2da15bf0 {NSURL=htt:\/\/tim.cstj.qc.ca\/cours\/xcode\/api_tim\/public\/index.php\/requetes_api\/?type=liste_pensees&amp;mode=rnd&amp;quant=5})]<\/pre>\n<p>&nbsp;<br \/>\n<span style=\"color: #ff0000;\"><strong>Action API.TIM.10<\/strong><\/span>\u00a0&#8211;\u00a0Corrigeons l&rsquo;URL (le &lsquo;p&rsquo; suivant &lsquo;htt&rsquo;)<\/p>\n<pre class=\"lang:swift decode:true\">let adresseURL = \"htt:\/\/tim.cstj.qc.ca\/cours\/xcode\/api_tim\/public\/index.php\/requetes_api\/?type=liste_pensees&amp;mode=rnd&amp;quant=5\"<\/pre>\n<p>&nbsp;<br \/>\n<strong>R\u00e9sultat:<\/strong><\/p>\n<pre class=\"lang:swift decode:true\">\/\/ [donneesViaURL: R\u00e9ussit]<\/pre>\n<p>&nbsp;<br \/>\n<span style=\"color: #ff0000;\"><strong>Action API.TIM.11<\/strong><\/span>\u00a0&#8211;\u00a0Validons la conversion JSON:<\/p>\n<pre class=\"lang:swift mark:10-23 decode:true\">        var penseeValidee = Dictionary&lt;String, String&gt;()\n        var erreur:NSError?\n        let adresseURL = \"\/cours\/xcode\/api_tim\/public\/index.php\/requetes_api\/?type=liste_pensees&amp;mode=rnd&amp;quant=5\"\n        let url = NSURL(string: adresseURL)\n        if let data = NSData(contentsOfURL:url!, options: nil, error: &amp;erreur){\n            \/\/ Ici, nous avons obtenu des donn\u00e9es vie une URL\n            penseeValidee[\"donneesViaURL\"] = \"R\u00e9ussit\"\n            if let resultat = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers, error: &amp;erreur) as? Dictionary&lt;String, AnyObject&gt;\n {\n                \/\/ Ici, nous avons des donn\u00e9es JSON valides.\n                penseeValidee[\"conversionJSON\"] = \"R\u00e9ussit\"\n                println(\"resultat: \\n\" + resultat.description)\n            } else \/\/ Erreur de conversion JSON\n            {\n                penseeValidee[\"conversionJSON\"] = \"Erreur de conversion JSON: \\(erreur)\"\n            }  \/\/ if let resultat\n        } else \/\/ Erreur: URL invalide\n        {\n            penseeValidee[\"donneesViaURL\"] = \"Erreur de lecture des donn\u00e9es: \\(erreur)\"\n        } \/\/ else = Erreur: URL\n        println(penseeValidee)\n<\/pre>\n<p>&nbsp;<br \/>\n<strong>R\u00e9sultat:<\/strong><\/p>\n<pre class=\"lang:swift decode:true \">\/\/ [donneesViaURL: R\u00e9ussit, conversionJSON: R\u00e9ussit]<\/pre>\n<p>&nbsp;<br \/>\n<span style=\"color: #ff0000;\"><strong>Action API.TIM.12<\/strong><\/span>\u00a0&#8211; Programmons une la\u00a0validation compl\u00e8te:<\/p>\n<pre class=\"lang:swift decode:true \">    override func viewDidLoad() {\n        super.viewDidLoad()\n        var penseeValidee = Dictionary&lt;String, String&gt;()\n        var erreur:NSError?\n        let adresseURL = \"\/cours\/xcode\/api_tim\/public\/index.php\/requetes_api\/?type=liste_pensees&amp;mode=rnd&amp;quant=5\"\n        let url = NSURL(string: adresseURL)\n        let penseeNumero = 3\n        if let data = NSData(contentsOfURL:url!, options: nil, error: &amp;erreur){\n            \/\/ Ici, nous avons obtenu des donn\u00e9es vie une URL\n            penseeValidee[\"donneesViaURL\"] = \"R\u00e9ussit\"\n            if let resultat = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers, error: &amp;erreur) as? Dictionary&lt;String, AnyObject&gt; {\n                \/\/ Ici, nous avons des donn\u00e9es JSON valides.\n                penseeValidee[\"conversionJSON\"] = \"R\u00e9ussit\"\n                \/\/ Obtenir une pensee de 'resultat'\n                if let lesPensees = (resultat[\"resultat\"]) as? Array&lt;Dictionary&lt;String, String&gt;&gt; {\n                    penseeValidee[\"CreationLesPensees\"] = \"Cr\u00e9ation du tableau des pens\u00e9es r\u00e9ussit.\"\n                    \/\/ Ici, il y a un tableau \u00e0 la cl\u00e9 'resultat'\n                    \/\/ Donc, obtenir une pens\u00e9e et son auteur\n                    let champ_pensee_auteur = \"pensee_auteur\"\n                    let champ_pensee_texte  = \"pensee_texte\"\n                    if let pensee_auteur = lesPensees[penseeNumero][champ_pensee_auteur] {\n                        penseeValidee[\"pensee_auteur\"] = pensee_auteur\n                    }  else { penseeValidee[\"pensee_auteur\"] = \"Erreur champ: '\\(champ_pensee_auteur)'\\n\" }\n                    if let pensee_texte = lesPensees[penseeNumero][champ_pensee_texte] {\n                        penseeValidee[\"pensee_texte\"] = pensee_texte\n                    }  else { penseeValidee[\"pensee_texte\"] = \"Erreur champ: '\\(champ_pensee_texte)'\\n\" }\n                } else \/\/ erreur d'acc\u00e8s avec le cl\u00e9 'r\u00e9sultat'\n                {\n                    penseeValidee[\"CreationLesPensees\"] = \"Erreur: Impossible de cr\u00e9er le tableau des pens\u00e9es \u00e0 partir de la cl\u00e9 'resultat'.\"\n                } \/\/ if let lesPensees\n            } else \/\/ Erreur de conversion JSON\n            {\n                penseeValidee[\"conversionJSON\"] = \"Erreur de conversion JSON: \\(erreur)\"\n            }  \/\/ if let resultat\n        } else \/\/ Erreur: URL invalide\n        {\n            penseeValidee[\"donneesViaURL\"] = \"Erreur de lecture des donn\u00e9es: \\(erreur)\"\n        } \/\/ if let data\n        println(penseeValidee)\n    } \/\/ viewDidLoad()\n<\/pre>\n<p>&nbsp;<\/p>\n<h3>Et si nous passions par une classe personnalis\u00e9e?<\/h3>\n<p>Voici un exemple d&rsquo;une classe de lecture d&rsquo;une source URL:JSON.<\/p>\n<pre class=\"lang:swift decode:true \">\/\/\n\/\/  DonneesDuneURL.swift\n\/\/  tester API-TIM partie 2\n\/\/\n\/\/  Created by Alain on 15-10-16.\n\/\/  Copyright (c) 2015 Production sur support. All rights reserved.\n\/\/\nimport Foundation\nclass DonneesDuneURL  {\n    var resultat:Dictionary&lt;String, AnyObject&gt;?\n    var erreurLien:Bool = true\n    var erreurConversion:Bool = true\n    var error:NSError?              \/\/ requit pour JSONSerialization\n    init(adresseURL:String) {\n        let url = NSURL(string: adresseURL)\n        \/\/ Obtenir les donn\u00e9es en format brut\n        if let data = NSData(contentsOfURL:url!, options: nil, error: nil) {\n            println(\"L'URL a retourn\u00e9 des donn\u00e9es!\")\n            erreurLien = false\n            \/\/ Convertir les donn\u00e9es brutes en format JSON et les placer\n            \/\/ dans resultat\n            resultat = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers, error: &amp;error) as? Dictionary\n            \/\/ V\u00e9rifier si la conversion a fonctionn\u00e9\n            if let err = error {\n                \/\/ Pour arriver ici, il faut que error != nil, donc de type NSError\n                println(\"Pour une raison \u00e9trange, la requ\u00eate a retourn\u00e9 une structure JSON mal form\u00e9e...: \\(error)\");\n            } else\n            {\n                \/\/ error est 'nil' donc il n'y a pas d'erreur!\n                println(\"Conversion JSON r\u00e9ussie\");\n                erreurConversion = false\n            }       \/\/ if let err\n        } else \/\/ if let data\n        {\n            println(\"Erreur: l'URL n'a pas retourn\u00e9 de donn\u00e9es!\")\n        }  \/\/ if let data\n    }  \/\/ init()\n    func descriptionErreurs()-&gt;String{\n        return \"erreurLien: \\(erreurLien), erreurConversion: \\(erreurConversion)\"\n    }\n}  \/\/ class DonneesDuneURL<\/pre>\n<p><strong>Note:<\/strong> Il y des traces dans la classe pour des besoins d&rsquo;apprentissage.<br \/>\n&nbsp;<br \/>\nAvec un exemple d&rsquo;utilisation:<\/p>\n<pre class=\"lang:swift decode:true \">    override func viewDidLoad() {\n        super.viewDidLoad()\n        let donneesAPartirDuneURL = DonneesDuneURL(adresseURL: \"htt:\/\/tim.cstj.qc.ca\/cours\/xcode\/api_tim\/public\/index.php\/requetes_api\/?type=liste_pensees&amp;mode=rnd&amp;quant=5\")\n        if let penseesValidees = donneesAPartirDuneURL.resultat?[\"resultat\"] as? Array&lt;Dictionary&lt;String, String&gt;&gt; {\n            for data in penseesValidees{\n                println(\"\\n----------------------------------\")\n                \/\/  println(\"x: \\(data)\\n\")\n                if let y = data[\"pensee_auteur\"]{\n                    println(\"L'auteur \\(y) a dit:\\n\")\n                }\n                if let y = data[\"pensee_texte\"]{\n                    println(y)\n                }\n            }  \/\/ for data in penseesValidees\n        } else\n        { \/\/ erreur avec les donn\u00e9es\n            println(donneesAPartirDuneURL.descriptionErreurs())\n        } \/\/ if let penseesValidees = donneesAPartirDuneURL\n   } \/\/ viewDidLoad()<\/pre>\n<p>&nbsp;<br \/>\nCe qui donne comme r\u00e9sultat:<\/p>\n<pre class=\"lang:swift decode:true \">----------------------------------\nL'auteur F\u00e9lix Leclerc a dit:\nLe mariage, c'est deux billets d'avion aller seulement, vers une \u00eele inconnue. On en revient \u00e0 la nage ou jamais.\n----------------------------------\nL'auteur Bouddha a dit:\nIl n'existe rien de constant si ce n'est le changement.\n----------------------------------\nL'auteur Jacques Chardonne a dit:\n...<\/pre>\n<p>&nbsp;<br \/>\nPassons maintenant \u00e0 la pr\u00e9sentation de \u00a0l&rsquo;API du site &lsquo;rottentomatoes.com&rsquo;<br \/>\n&nbsp;<\/p>\n<hr \/>\n<h1>API de rottenTomatoes<\/h1>\n<p>&nbsp;<br \/>\nLe site &lsquo;RottenTomatoes&rsquo; propose une API d&rsquo;acc\u00e8s aux donn\u00e9es qu&rsquo;il compile. \u00a0Ces donn\u00e9es nous renseignent sur des films, \u00a0les critiques, les acteurs, les personnages, &#8230;<br \/>\nPour interroger l&rsquo;api de\u00a0rottentomatoes, il suffit de suivre l&rsquo;URL suivante:<br \/>\n&nbsp;<\/p>\n<blockquote><p>http:\/\/api.rottentomatoes.com\/api\/public\/v1.0\/movies.json?apikey=<span style=\"color: #ff0000;\">VOTRECLE<\/span>&amp;q=<span style=\"color: #ff0000;\">MODELE_DE_RECHERCHE<\/span>&amp;page_limit=<span style=\"color: #ff0000;\">NB_PAGES<\/span><\/p><\/blockquote>\n<p>&nbsp;<br \/>\nComme par exemple,\u00a0http:\/\/api.rottentomatoes.com\/api\/public\/v1.0\/movies.json?apikey=<span style=\"color: #ff0000;\">sn896rbfs3vrkcgdmndkb2<\/span>&amp;q=<span style=\"color: #ff0000;\">Star<\/span>&amp;page_limit=<span style=\"color: #ff0000;\">10<\/span><br \/>\nNote: La cl\u00e9 de l&rsquo;exemple est invalide. \u00a0Vous devez la remplacer par celle que vous avez obtenue de rottentomatoes.\u00a0\u00a0La limite de pages fix\u00e9e par l&rsquo;api est de 50 pages.<br \/>\nLa requ\u00eate pr\u00e9c\u00e9dente devrait nous retourner une structure JSON contenant une liste d&rsquo;au plus 10 films dont la cha\u00eene &lsquo;Star&rsquo; appara\u00eet dans le titre du film.<br \/>\nPour obtenir, \u00e0 partir du r\u00e9seau Internet, des donn\u00e9es en format JSON et cr\u00e9er un dictionnaire, il suffira d&rsquo;utiliser la technique pr\u00e9sent\u00e9e plus haut:<\/p>\n<blockquote><p>NSData.dataWithContentsOfURL et<br \/>\nNSJSONSerialization.JSONObjectWithData<\/p><\/blockquote>\n<p>&nbsp;<\/p>\n<hr \/>\n<h2>\u00c9tape 1 &#8211; Obtenir des donn\u00e9es du web<\/h2>\n<p><span style=\"color: #ff0000;\"><strong>Action 1.1<\/strong><\/span>\u00a0&#8211; Ouvrons le projet <a href=\"https:\/\/github.com\/puyansude\/Projet-de-RottenTomatoes-version-de-depart\/archive\/master.zip\">Projet &#8211; RottenTomatoes version swift &#8211; depart<\/a>\u00a0et ajoutons le code suivant \u00e0 la m\u00e9thode &lsquo;rechercherFilms&rsquo; de la classe contr\u00f4leur de la sc\u00e8ne principale.<br \/>\n<strong>\u00a0<span style=\"color: #ff0000;\">Note: \u00a0Il faut inscrire votre cl\u00e9 programmeur dans la classe &lsquo;cle.swift&rsquo;<\/span><\/strong><\/p>\n<pre class=\"toolbar:1 lang:default decode:true\">   \/\/ *************************************************************************************************\n    func rechercherFilms(film:String) -&gt; Bool {\n        println(\"rechercherFilms: \\(film)\")\n        progression.startAnimating()\n        let adresseURL = \"http:\/\/api.rottentomatoes.com\/api\/public\/v1.0\/movies.json?apikey=\\(CLE_API)&amp;q=\\(film)&amp;page_limit=\\(NB_FILMS)\"\n        let url = NSURL(string: adresseURL)\n        \/\/ Obtenir les donn\u00e9es en format brut\n        let data = NSData(contentsOfURL:url!, options: nil, error: nil)\n        \/\/ Si data est vide alors quitter la m\u00e9thode\n        if let resultat = data {\n            println(\"L'URL a retourn\u00e9 des donn\u00e9es!\")\n        } else\n        {\n            println(\"Erreur: l'URL n'a pas retourn\u00e9 de donn\u00e9es!\")\n            return false\n        }\n        \/\/ Convertir les donn\u00e9es brutes en format JSON et les placer\n        \/\/ dans tableauDesFilms\n        var error:NSError?\n        self.tableauDesFilms = NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.MutableContainers, error: &amp;error) as! Dictionary&lt;String, AnyObject&gt;\n        \/\/ V\u00e9rifier si la conversion a fonctionn\u00e9\n        if let err = error {\n            \/\/ Pour arriver ici, il faut que error != nil, donc de type NSError\n            println(\"Pour une raison \u00e9trange, la requ\u00eate chez 'rottentomatoes' a retourn\u00e9e une structure JSON mal form\u00e9e...: \\(error)\");\n            return false\n        } else\n        {\n            \/\/ error est 'nil' donc il n'y a pas d'erreur!\n            println(\"Conversion JSON r\u00e9ussie\");\n        }\n        println(\"tableauDesFilms = \\(self.tableauDesFilms)\")\n        progression.stopAnimating()\n        return true\n    } \/\/ rechercherFilms<\/pre>\n<p>&nbsp;<br \/>\n<span style=\"color: #ff0000;\"><strong>Action\u00a01.2<\/strong><\/span>\u00a0&#8211;\u00a0Testons l&rsquo;application. \u00a0Remarquez que la m\u00e9thode &lsquo;rechercherFilm&rsquo; est appel\u00e9e dans &lsquo;viewDidLoad&rsquo;.<br \/>\n<img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-2215\" src=\"\/xcode\/wp-content\/uploads\/2014\/09\/rotten_capture_01.png\" alt=\"rotten_capture_01\" width=\"1114\" height=\"929\" \/><br \/>\n&nbsp;<br \/>\nNous devrions obtenir le r\u00e9sultat suivant dans la zone &lsquo;debug\u00a0\u00bb \u00a0d&rsquo;Xcode:<\/p>\n<pre class=\"toolbar:1 lang:default decode:true\"> tableauDesFilms = {\n    \"link_template\" = \"http:\/\/api.rottentomatoes.com\/api\/public\/v1.0\/movies.json?q={search-term}&amp;page_limit={results-per-page}&amp;page={page-number}\";\n    links =     {\n        next = \"http:\/\/api.rottentomatoes.com\/api\/public\/v1.0\/movies.json?q=star&amp;page_limit=1&amp;page=2\";\n        self = \"http:\/\/api.rottentomatoes.com\/api\/public\/v1.0\/movies.json?q=star&amp;page_limit=1&amp;page=1\";\n    };\n    movies =     (  \/\/  &lt;-- tableau de films\n                {   \/\/  &lt;-- dictionnaire de donn\u00e9es du premier film de la liste\n            \"abridged_cast\" =             (\n                                {\n                    characters =                     (\n                        \"Anakin Skywalker\/Darth Vader\"\n                    );\n                    id = 162652153;\n                    name = \"Hayden Christensen\";\n                },\n                                {\n                    characters =                     (\n                        \"Obi-Wan Kenobi\"\n                    );\n                    id = 162652152;\n                    name = \"Ewan McGregor\";\n                },\n                                {\n                    characters =                     (\n                        \"R2-D2\"\n                    );\n                    id = 418638213;\n                    name = \"Kenny Baker\";\n                },\n                                {\n                    characters =                     (\n                        \"Ruwee Naberrie\"\n                    );\n                    id = 548155708;\n                    name = \"Graeme Blundell\";\n                },\n                                {\n                    characters =                     (\n                        \"Captain Colton\"\n                    );\n                    id = 358317901;\n                    name = \"Jeremy Bulloch\";\n                }\n            );\n            \"alternate_ids\" =             {\n                imdb = 0121766;\n            };\n            \"critics_consensus\" = \"This sixth and final installment of George Lucas' epic space opera will please die-hard fanatics and non-believers alike -- largely due to awesome digital effects and the sheer power of the mythology.\";\n            id = 9;\n            links =             {\n                alternate = \"http:\/\/www.rottentomatoes.com\/m\/star_wars_episode_iii_revenge_of_the_sith_3d\/\";\n                cast = \"http:\/\/api.rottentomatoes.com\/api\/public\/v1.0\/movies\/9\/cast.json\";\n                clips = \"http:\/\/api.rottentomatoes.com\/api\/public\/v1.0\/movies\/9\/clips.json\";\n                reviews = \"http:\/\/api.rottentomatoes.com\/api\/public\/v1.0\/movies\/9\/reviews.json\";\n                self = \"http:\/\/api.rottentomatoes.com\/api\/public\/v1.0\/movies\/9.json\";\n                similar = \"http:\/\/api.rottentomatoes.com\/api\/public\/v1.0\/movies\/9\/similar.json\";\n            };\n            \"mpaa_rating\" = \"PG-13\";\n            posters =             {\n                detailed = \"http:\/\/content8.flixster.com\/movie\/10\/94\/47\/10944718_det.jpg\";\n                original = \"http:\/\/content8.flixster.com\/movie\/10\/94\/47\/10944718_ori.jpg\";\n                profile = \"http:\/\/content8.flixster.com\/movie\/10\/94\/47\/10944718_pro.jpg\";\n                thumbnail = \"http:\/\/content8.flixster.com\/movie\/10\/94\/47\/10944718_mob.jpg\";\n            };\n            ratings =             {\n                \"audience_rating\" = Upright;\n                \"audience_score\" = 65;\n                \"critics_rating\" = \"Certified Fresh\";\n                \"critics_score\" = 80;\n            };\n            \"release_dates\" =             {\n                dvd = \"2005-11-01\";\n            };\n            runtime = 140;\n            synopsis = \"\";\n            title = \"Star Wars: Episode III - Revenge of the Sith 3D\";\n            year = 2005;  \/\/ &lt;-- date du premier film de la liste\n        },  \/\/ &lt;-- fin des donn\u00e9es du premier film de la liste\n               {  \/\/ &lt;-- deuxi\u00e8me film de la liste\n            \"abridged_cast\" =             ();\n            ...\n            \"mpaa_rating\" = \"PG-13\";\n            posters =             {\n                original = \"http:\/\/content9.flixster.com\/movie\/11\/17\/38\/11173843_ori.jpg\";\n            };\n            runtime = 127;\n            synopsis = \"\";\n            title = \"Star Trek\";\n            year = 2009;\n        },\n        ...\n    );\n    total = 1319;\n}<\/pre>\n<p>&nbsp;<br \/>\nEn analysant la structure pr\u00e9c\u00e9dente, il est possible d&rsquo;\u00e9noncer les\u00a0<a href=\"http:\/\/fr.wikipedia.org\/wiki\/Axiome\">axiomes<\/a>\u00a0suivants:<\/p>\n<ol>\n<li>Le dictionnaire contient un tableau de films \u00e0 l&rsquo;\u00e9l\u00e9ment dictionnaire[\u00ab\u00a0movies\u00a0\u00bb].<\/li>\n<li>Toutes les informations d&rsquo;un film sont disponibles \u00e0 dictionnaire[\u00ab\u00a0movies\u00a0\u00bb][indiceDuFilm].<\/li>\n<li>\u00a0[\u00ab\u00a0movies\u00a0\u00bb][indiceDuFilm] retourne un dictionnaire<\/li>\n<li>Une information sur un film est disponible \u00e0\u00a0dictionnaire[\u00ab\u00a0movies\u00a0\u00bb][indiceDuFilm] [\u00ab\u00a0nomChamp\u00a0\u00bb].<\/li>\n<\/ol>\n<p>Ainsi, pour obtenir le\u00a0titre du premier film de la liste nous \u00e9crirons:<\/p>\n<ul>\n<li>let titreDuPremierFilm = (((tableauDesFilms[\u00ab\u00a0movies\u00a0\u00bb] as! Array)[0] as Dictionary&lt;String,AnyObject&gt;)[\u00ab\u00a0title\u00a0\u00bb]!) as! String<\/li>\n<\/ul>\n<p>Et pour l&rsquo;ann\u00e9e:<\/p>\n<ul>\n<li>let anneeDuPremierFilm = (((tableauDesFilms[\u00ab\u00a0movies\u00a0\u00bb] as! Array)[0] as Dictionary&lt;String,AnyObject&gt;)[\u00ab\u00a0year\u00a0\u00bb]!) as! Int<\/li>\n<\/ul>\n<p><strong>QUESTION<\/strong>: \u00a0Comment obtenir l&rsquo;affiche originale du deuxi\u00e8me film?<br \/>\n&nbsp;<br \/>\n<span style=\"color: #ff0000;\"><strong>Action\u00a01.3<\/strong><\/span>\u00a0&#8211;\u00a0Affichons le titre des films re\u00e7us (\u00e0 la fin de la m\u00e9thode: &lsquo;rechercherFilms&rsquo;)<\/p>\n<pre class=\"toolbar:1 lang:default decode:true\">        \/\/ Afficher le titre des films\n        let films = self.tableauDesFilms[\"movies\"] as! Array&lt;Dictionary&lt;String, AnyObject&gt;&gt;\n        var _titre = \"\"\n        var _annee = 0\n        for courant in films {\n            if let titre = courant[\"title\"] as? String {\n                _titre = titre\n            } else { _titre = \"n\/a\" }\n            if let annee = courant[\"year\"] as? Int {\n                _annee = annee\n            } else { _annee = -1 }\n            println(\"Titre du film: \\(_titre) - date:\\(_annee)\")\n        } \/\/ for ... in films<\/pre>\n<p>&nbsp;<br \/>\nou bien ainsi:<\/p>\n<pre class=\"lang:swift decode:true\">        \/\/ Note: Attention, ne valide pas la pr\u00e9sence du champ 'movies'\n       for courant in tableauDesFilms[\"movies\"] as! Array&lt;Dictionary&lt;String, AnyObject&gt;&gt; {\n            if let titre = courant[\"title\"] as? NSString {\n                print(\"Titre du film: \\(titre)\")\n            }\n            if let annee = courant[\"year\"] as? NSNumber {\n                println(\" - date:\\(annee)\")\n            }\n        } \/\/ for ... in films<\/pre>\n<p>&nbsp;<\/p>\n<hr \/>\n<h2>\u00c9tape 2 &#8211; Actualiser la requ\u00eate suite \u00e0 &lsquo;textFieldShouldReturn&rsquo;<\/h2>\n<p>&nbsp;<br \/>\nRemarquer qu&rsquo;il y a une zone de recherche en haut \u00e0 droite de l&rsquo;application. \u00a0Nous allons utiliser la m\u00e9thode de d\u00e9l\u00e9gation &lsquo;textFieldShouldReturn&rsquo; du &lsquo;UITextField&rsquo;\u00a0\u00a0pour relancer la requ\u00eate vers l&rsquo;api de rottenTomatoes.<br \/>\n&nbsp;<br \/>\n<a href=\"\/xcode\/wp-content\/uploads\/2013\/10\/rotten-002.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-562\" src=\"\/xcode\/wp-content\/uploads\/2013\/10\/rotten-002.png\" alt=\"rotten-002\" width=\"269\" height=\"71\" \/><\/a><br \/>\n&nbsp;<br \/>\n<span style=\"color: #ff0000;\"><strong>Action 2.1<\/strong><\/span>\u00a0&#8211;\u00a0Ajoutons le code suivant \u00e0 la m\u00e9thode &lsquo;textFieldShouldReturn&rsquo;\u00a0de la classe contr\u00f4leur de la sc\u00e8ne principale.<\/p>\n<pre class=\"lang:default decode:true\">func textFieldShouldReturn(textField: UITextField) -&gt; Bool {\n  println(\"textFieldShouldReturn\")\n  \/\/ Convertir la chaine en format 'escaped' pour le web, par exemple, remplacer les espaces par %20, ...\n  let escapedText = textField.text.stringByAddingPercentEscapesUsingEncoding(NSUTF8StringEncoding)!\n  println(\"escapedText = \\(escapedText)\")\n  \/\/ Relancer la requete vers rottenTomatoes\n  rechercherFilms(escapedText)\n  \/\/ Actualiser les cellules du UICollectionView\n  collectionDeFilms.reloadData()\n  \/\/----------------------------------\n  textField.resignFirstResponder()\n  progression.stopAnimating()\n  return true\n} \/\/ textFieldShouldReturn\n<\/pre>\n<p>&nbsp;<br \/>\n<span style=\"color: #ff0000;\"><strong>Action\u00a02.2<\/strong><\/span>\u00a0&#8211;\u00a0Testons l&rsquo;application<br \/>\n&nbsp;<br \/>\n<iframe loading=\"lazy\" width=\"700\" height=\"394\" src=\"https:\/\/www.youtube.com\/embed\/SgfEfEuKYrU?feature=oembed\" frameborder=\"0\" allowfullscreen><\/iframe><br \/>\n&nbsp;<\/p>\n<hr \/>\n<h2>\u00c9tape 3 &#8211; Renseigner les \u00a0cellules du UICollectionView<\/h2>\n<p>&nbsp;<br \/>\nNous savons qu&rsquo;il est possible de cr\u00e9er un objet de type &lsquo;UIImage&rsquo; \u00e0 partir du nom d&rsquo;un fichier livr\u00e9 avec l&rsquo;application de la fa\u00e7on suivante:<\/p>\n<blockquote><p>UIImage(Named:\u00a0\u00bbpochette.jpg\u00a0\u00bb)<\/p><\/blockquote>\n<p>Mais lorsque que ce fichier est stock\u00e9 dans le r\u00e9seau Internet il faut proc\u00e9der ainsi:<\/p>\n<blockquote><p>UIImage(data:NSData.dataWithContentsOfURL(NSURL(string: urlImage), options: nil, error: nil))<\/p><\/blockquote>\n<p>Note: La qualit\u00e9 de l&rsquo;exp\u00e9rience utilisateur va \u00eatre affect\u00e9e par le\u00a0chargement d&rsquo;un grand nombre d&rsquo;images. \u00a0Plus tard, nous proposerons une solution \u00e0 ce probl\u00e8me.<br \/>\n&nbsp;<br \/>\n<span style=\"color: #ff0000;\"><strong>Action 3.1<\/strong><\/span>\u00a0&#8211;\u00a0\u00a0Ajoutons le code suivant \u00e0 la m\u00e9thode &lsquo;cellForItem&#8230;&rsquo; du fichier ViewController.m\u00a0\u00bb<\/p>\n<pre class=\"toolbar:1 lang:default mark:12 decode:true\">    \/\/ *************************************************************************************************\n    func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -&gt; UICollectionViewCell\n    \/\/ *******************************************************\n    {\n         var celluleCourante = collectionView.dequeueReusableCellWithReuseIdentifier(\"modeleCellule\", forIndexPath: indexPath) as! CelluleRotten\n        \/\/\/ *** Temporaire: \u00c0 effacer!\n        \/\/ celluleCourante.titre!.text = \"Cellule no: \\(indexPath.row)\"\n        if let films = tableauDesFilms[\"movies\"] as? Array&lt;AnyObject&gt;\n        {\n            celluleCourante.titre.text = (films[indexPath.row] as! Dictionary&lt;String, AnyObject&gt;)[\"title\"] as? String\n            \/\/ Utilisation d'un NSString pour avoir acc\u00e8s \u00e0 la m\u00e9thode NSString.rangeOfString()\n            var urlImage = ((films[indexPath.row] as! Dictionary&lt;String,AnyObject&gt;)[\"posters\"] as! Dictionary&lt;String,NSString&gt;)[\"original\"]!\n            \/\/ Patch ajout\u00e9e 2015.10.01\t\\ - rotten ne fournit plus de grosses images dans le feed json\n            \/\/ Il faut maintenant faire un peu plus de travail\n            \/*\n            http:\/\/resizing.flixster.com\/AhKHxRwazY3brMINzfbnx-A8T9c=\/54x80\/dkpu1ddg7pbsk.cloudfront.net\/movie\/11\/13\/43\/11134356_ori.jpg\n            ... devient ...\n            http:\/\/dkpu1ddg7pbsk.cloudfront.net\/movie\/11\/13\/43\/11134356_ori.jpg\n            *\/\n            let posDepart = urlImage.rangeOfString(\"dkpu1ddg7pbsk.cloudfront.net\").location\n            if posDepart != NSNotFound  {\n                urlImage = \"http:\/\/\" + urlImage.substringWithRange(NSRange(location: posDepart, length: urlImage.length - posDepart))\n            }\n            \/\/ Version bloquante de la requ\u00eate\n            celluleCourante.filmImage.image = UIImage(data:NSData(contentsOfURL: NSURL(string: urlImage as! String)!, options: nil, error: nil)!)\n        }\n        return celluleCourante;\n    } \/\/ cellForItemAtIndexPath<\/pre>\n<p>&nbsp;<br \/>\n<span style=\"color: #ff0000;\"><strong>Action 3.2<\/strong><\/span>\u00a0&#8211;\u00a0Corrigeons la valeur de retour de \u00a0la m\u00e9thode &lsquo;numberOfItems&#8230;&rsquo;<\/p>\n<pre class=\"toolbar:1 lang:default mark:2 decode:true\">func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -&gt; Int {\n  \/\/ films disponibles?\n  if let films = tableauDesFilms[\"movies\"] as? Array&lt;Dictionary&lt;String, AnyObject&gt;&gt;\n    {\n       return films.count\n    }\n    else\n    {\n       return 0\n    }\n} \/\/ numberOfItemsInSection\n<\/pre>\n<p>&nbsp;<br \/>\n<span style=\"color: #ff0000;\"><strong>Action\u00a03.3<\/strong><\/span>\u00a0&#8211;\u00a0Ajoutons le code suivant \u00e0 la m\u00e9thode &lsquo;prepareForSegue&rsquo;<\/p>\n<pre class=\"toolbar:1 lang:default mark:7-8 decode:true\">\/\/ Passer les info \u00e0 la sc\u00e8ne de d\u00e9tail\n\/\/ *************************************************************************************************\noverride func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {\n  var vc = segue.destinationViewController as DetailFilmViewController\n  \/\/ Passer les informations de la s\u00e9lection courante \u00e0 la sc\u00e8ne de d\u00e9tail\n  let selectionCourante = collectionDeFilms.indexPathForCell(sender as! UICollectionViewCell)?.row\n  vc.detailFilm = (tableauDesFilms[\"movies\"] as! Array)[selectionCourante!] as Dictionary&lt;String, AnyObject&gt;\n} \/\/ \/\/ Passer les info \u00e0 la sc\u00e8ne de d\u00e9tail<\/pre>\n<p>&nbsp;<br \/>\n<span style=\"color: #ff0000;\"><strong>Action\u00a03.4<\/strong><\/span>\u00a0&#8211;\u00a0Augmentons le nombre maximum de films pour la requ\u00eate vers l&rsquo;api de rottenTomatoes<\/p>\n<pre class=\"toolbar:1 lang:default mark:2 decode:true\">\/\/  ViewController.swift\nlet NB_FILMS = \"50\"<\/pre>\n<p>&nbsp;<br \/>\n<span style=\"color: #ff0000;\"><strong>Action\u00a03.5<\/strong><\/span>\u00a0&#8211;\u00a0Renseignons quelques champs de la sc\u00e8ne &lsquo;D\u00e9tail&rsquo;<\/p>\n<pre class=\"lang:swift decode:true\">        self.detailTitre.text       = detailFilm[\"title\"] as NSString\n        println(\"S\u00e9lection courante: \\(detailFilm)\")\n        if let df = detailFilm {\n          self.detailTitre.text       = df[\"title\"] as? String\n          \/\/ Tester l'ann\u00e9e...\n          if let temp = df[\"year\"] as? Int {\n              self.detailAnnee.text = temp.description\n          }\n          \/\/ Tester la dur\u00e9e\n          if let temp = df[\"runtime\"] as? Int {\n             self.detailDuree.text = temp.description\n          }\n      }<\/pre>\n<p>&nbsp;<br \/>\n<span style=\"color: #ff0000;\"><strong>Action\u00a03.6<\/strong><\/span>\u00a0&#8211;\u00a0Testons l&rsquo;application. \u00a0<span style=\"color: #ff0000;\">Vous allez remarquer un important manque de r\u00e9ponse de l&rsquo;application.<\/span><br \/>\n&nbsp;<br \/>\n<iframe loading=\"lazy\" width=\"700\" height=\"394\" src=\"https:\/\/www.youtube.com\/embed\/bsFFn6ULjyI?feature=oembed\" frameborder=\"0\" allowfullscreen><\/iframe><br \/>\n&nbsp;<br \/>\n<a href=\"\/xcode\/wp-content\/uploads\/2014\/09\/Projet-RottenTomatoes-version-swift-solution-etape-1-a-3.zip\">Projet &#8211; RottenTomatoes version swift &#8211; solution \u00e9tapes 1 a 3<\/a><br \/>\n&nbsp;<\/p>\n<hr \/>\n<h2>\u00c9tape 4 &#8211; Am\u00e9liorer l&rsquo;exp\u00e9rience utilisateur<\/h2>\n<p>&nbsp;<br \/>\nPr\u00e9sentement, les requ\u00eates web de l&rsquo;application sont bloquantes, C-A-D que l&rsquo;application attend la r\u00e9ponse de la requ\u00eate avant de passer \u00e0 la ligne de code suivante. \u00a0Cela a pour effet de bloquer aussi l&rsquo;interactivit\u00e9 de l&rsquo;application.<br \/>\nLe &lsquo;framework&rsquo; cocoa nous propose la m\u00e9thode de classe\u00a0&lsquo;<strong>NSURLConnection.<span style=\"color: #ff0000;\">sendAsynchronousRequest<\/span><\/strong>&lsquo; pour lancer une requ\u00eate URL\u00a0non bloquante:<\/p>\n<blockquote><p>\u00a0NSURLConnection.<span style=\"color: #ff0000;\">\u00a0sendAsynchronousRequest(<br \/>\n<\/span>\u00a0 \u00a0<span style=\"color: #ff0000;\">UneRequete,<br \/>\n<\/span><span style=\"color: #ff0000;\">\u00a0 \u00a0queue<\/span>: uneFileExecution,<br \/>\n<span style=\"color: #ff0000;\">\u00a0 \u00a0completionHandler<\/span>:UnBlocDeCodeAExecuter \u00a0\/\/ \u00e0 la r\u00e9ception des donn\u00e9es<br \/>\n)<\/p><\/blockquote>\n<p>&nbsp;<br \/>\nLe bloc de code (fonction anonyme, fonction en ligne) sera copi\u00e9\u00a0en file (queue) et ex\u00e9cut\u00e9, en parall\u00e8le avec l&rsquo;application, lorsque les donn\u00e9es seront obtenues.<br \/>\nUn bloc de code a la syntaxe suivante:<\/p>\n<blockquote><p>{ (<strong><span style=\"color: #008000;\">param1: Type, param2:Type?,&#8230;<\/span><\/strong>) -&gt; <strong><span style=\"color: #666699;\">Void in<\/span><\/strong><br \/>\nif let x\u00a0= param2 {<br \/>\n&#8230;<br \/>\n}<br \/>\n} \/\/ fin du bloc<\/p><\/blockquote>\n<p>&nbsp;<br \/>\nLe param\u00e8tre <span style=\"color: #ff0000;\">completionHandler de\u00a0NSURLConnection.\u00a0sendAsynchronousReques<span style=\"color: #000000;\"> attend un bloc dont la signature est:<\/span><\/span><\/p>\n<blockquote><p>{ \u00a0(response: NSURLResponse!, data: NSData!, error: NSError!) -&gt; Void in<br \/>\n}<\/p><\/blockquote>\n<p>&nbsp;<br \/>\nPr\u00e9sentement, nous utilisons la syntaxe suivante pour lancer une requ\u00eate vers l&rsquo;api de rottenTomatoes:<\/p>\n<pre class=\"toolbar:1 lang:default mark:4 decode:true\">...\n\/\/ Obtenir les donn\u00e9es en format brut\nNSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:URLFilm]];\n...\n\/\/ Convertir les donn\u00e9es brutes en format JSON\ntableauDesFilms = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:&amp;error];\n...<\/pre>\n<p>&nbsp;<br \/>\n<span style=\"color: #ff0000;\"><strong>Action 4.1<\/strong><\/span>\u00a0&#8211;\u00a0Modifions la m\u00e9thode &lsquo;rechercherFilms&rsquo; pour rendre la requ\u00eate non bloquante<\/p>\n<pre class=\"lang:default decode:true\">    \/\/ *************************************************************************************************\n    func rechercherFilms(film:String) -&gt; Bool {\n        println(\"rechercherFilms: \\(film)\")\n        progression.startAnimating()\n        let adresseURL = \"http:\/\/api.rottentomatoes.com\/api\/public\/v1.0\/movies.json?apikey=\\(CLE_API)&amp;q=\\(film)&amp;page_limit=\\(NB_FILMS)\"\n        \/\/ Requete via URL non bloquante\n        let url: NSURL = NSURL(string: adresseURL)!\n        let requete: NSURLRequest = NSURLRequest(URL: url)\n        \/\/ Obtenir la file courante\n        let queue:NSOperationQueue = NSOperationQueue.currentQueue()!  \/\/ Attention \u00e0: NSOperationQueue()\n        NSURLConnection.sendAsynchronousRequest(requete, queue: queue, completionHandler:{ (response: NSURLResponse!, data: NSData!, error: NSError!) -&gt; Void in\n            if let err = error {\n                println(\"Erreur avec la requ\u00eate: \\(err)\")\n            } \/\/ if err\n            else\n            { \/\/ !err avec la requ\u00eate\n                \/\/ Note: Il faut utiliser self.nomVariable lorsque nous sommes dans une fn de type 'closure'\n               self.tableauDesFilms = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers, error: nil) as! Dictionary&lt;String, AnyObject&gt;\n                \/\/ println(\"R\u00e9sultat de la requ\u00eate: \\(self.tableauDesFilms)\")\n                \/\/ Afficher le titre des films\n                let films = self.tableauDesFilms[\"movies\"] as! Array&lt;Dictionary&lt;String, AnyObject&gt;&gt;\n                var _titre = \"\"\n                var _annee = 0\n                for courant in films {\n                    if let titre = courant[\"title\"] as? String {\n                        _titre = titre\n                    } else { _titre = \"n\/a\" }\n                    if let annee = courant[\"year\"] as? Int {\n                        _annee = annee\n                    } else { _annee = -1 }\n                    println(\"Titre du film: \\(_titre) - date:\\(_annee)\")\n                } \/\/ for ... in films\n                \/\/ Recharger le CollectionView\n                self.collectionDeFilms.reloadData()\n                self.nbResultat.text = \"\\(films.count)\"\n                self.progression.stopAnimating()\n            } \/\/ !err\n          } \/\/ completionHandler\n        ) \/\/ sendAsynchronousRequest\n        return true\n    } \/\/ rechercherFilms<\/pre>\n<p>&nbsp;<br \/>\n<span style=\"color: #ff0000;\"><strong>Action\u00a04.2<\/strong><\/span>\u00a0&#8211;\u00a0Testons l&rsquo;application.<br \/>\nVous allez remarquer que la sc\u00e8ne principale est affich\u00e9e imm\u00e9diatement. \u00a0 Pr\u00e9c\u00e9demment, la sc\u00e8ne \u00e9tait affich\u00e9e suite au traitement de la requ\u00eate web qui bloquait l&rsquo;ex\u00e9cution de l&rsquo;application.<br \/>\nPar contre, le chargement des pochettes de films est encore bloquant.<br \/>\nUtilisons la m\u00eame technique pour charger les images via le r\u00e9seau Internet.<br \/>\n&nbsp;<br \/>\n<span style=\"color: #ff0000;\"><strong>Action\u00a04.3<\/strong><\/span>\u00a0&#8211;\u00a0Dans la m\u00e9thode &lsquo;<strong>cellForItemAtIndexPath<\/strong>&lsquo;, rempla\u00e7ons la ligne de code \u00a0qui charge l&rsquo;image via une URL par:<\/p>\n<pre class=\"toolbar:1 lang:default mark:6 decode:true\">    \/\/ *************************************************************************************************\n    func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -&gt; UICollectionViewCell\n    {\n         var celluleCourante = collectionView.dequeueReusableCellWithReuseIdentifier(\"modeleCellule\", forIndexPath: indexPath) as! CelluleRotten\n        \/\/ V\u00e9rifier s'il la cl\u00e9 'movie' est pr\u00e9sente dans le dictionnaire.\n        if let films = tableauDesFilms[\"movies\"] as? Array&lt;AnyObject&gt;\n        {\n            celluleCourante.titre.text = (films[indexPath.row] as! Dictionary&lt;String, AnyObject&gt;)[\"title\"] as? String\n            \/\/ Utilisation d'un NSString pour avoir acc\u00e8s \u00e0 la m\u00e9thode NSString.rangeOfString()\n            var urlImage = ((films[indexPath.row] as! Dictionary&lt;String,AnyObject&gt;)[\"posters\"] as! Dictionary&lt;String,NSString&gt;)[\"original\"]!\n            \/\/ Patch ajout\u00e9e 2015.10.01\t\\ - rotten ne fournit plus de grosses images dans le feed jason\n            \/\/ Il faut maintenant faire un peu plus de travail\n            \/*\n                http:\/\/resizing.flixster.com\/AhKHxRwazY3brMINzfbnx-A8T9c=\/54x80\/dkpu1ddg7pbsk.cloudfront.net\/movie\/11\/13\/43\/11134356_ori.jpg\n                ... devient ...\n                http:\/\/dkpu1ddg7pbsk.cloudfront.net\/movie\/11\/13\/43\/11134356_ori.jpg\n            *\/\n            let posDepart = urlImage.rangeOfString(\"dkpu1ddg7pbsk.cloudfront.net\").location\n            if posDepart != NSNotFound  {\n                urlImage = \"http:\/\/\" + urlImage.substringWithRange(NSRange(location: posDepart, length: urlImage.length - posDepart))\n            }\n            \/\/ Version bloquante de la requ\u00eate\n            \/\/ celluleCourante.filmImage.image = UIImage(data:NSData(contentsOfURL: NSURL(string: URLImageCorrigee)!, options: nil, error: nil)!)\n            \/\/ Version non bloquante de la requ\u00eate\n            \/\/ Utiliser un 'place holder'\n            celluleCourante.filmImage.image = UIImage(named: \"loading.gif\")\n            \/\/ Pr\u00e9parer et lancer la requ\u00eate\n            let requeteImage = NSURLRequest(URL: NSURL(string:urlImage as! String)!)\n            let queue:NSOperationQueue = NSOperationQueue.currentQueue()!  \/\/ Attention \u00e0: NSOperationQueue()\n            NSURLConnection.sendAsynchronousRequest(requeteImage,\n                queue: queue,\n                completionHandler:{ (response: NSURLResponse!, data: NSData!, error: NSError!) -&gt; Void in\n                    if let err = error {\n                        println(\"Erreur avec la requ\u00eate: \\(err)\")\n                    } \/\/ if err\n                    else\n                    {\n                        celluleCourante.filmImage.image = UIImage(data: data)\n                    } \/\/ for error\n                } \/\/ completionHandler\n            ) \/\/ NSURLConnection.sendAsynchronousRequest\n        }  \/\/ if let films = tableauDesFilms[\"movies\"]\n        return celluleCourante\n    } \/\/ cellForItemAtIndexPath\n<\/pre>\n<p>&nbsp;<br \/>\n<span style=\"color: #ff0000;\"><strong>Action\u00a04.4<\/strong><\/span>\u00a0&#8211;\u00a0\u00c0 vous de modifier la classe de la sc\u00e8ne &lsquo;d\u00e9tail&rsquo; pour que le chargement des quatre affiches ne soit plus bloquant.<br \/>\n<span style=\"color: #ff0000;\"><strong>Action\u00a04.5<\/strong><\/span>\u00a0&#8211;\u00a0\u00c0 vous de renseigner les champs\u00a0de la sc\u00e8ne &lsquo;d\u00e9tail&rsquo;<br \/>\n<a href=\"\/xcode\/wp-content\/uploads\/2014\/09\/Projet-RottenTomatoes-version-swift-projet-final-sans-detail.zip\">Projet &#8211; RottenTomatoes version swift &#8211; projet final sans detail<\/a><\/p>\n<hr \/>\n<h1>Simplifier l&rsquo;utilisation de JSON<\/h1>\n<p>(Apr\u00e8s un dur labeur, l&rsquo;aisance)<br \/>\nIl existe, dans le r\u00e9seau Internet, des classes Swift &lsquo;open source&rsquo; qui facilitent le travail avec une structure JSON.<br \/>\nUne de ces classes est propos\u00e9e par\u00a0Pinglin Tang. \u00a0Elle est disponible ici (version 2.2.0 pour Xcode 6.4):<br \/>\n<a href=\"https:\/\/github.com\/SwiftyJSON\/SwiftyJSON\/releases\/tag\/2.2.0\">https:\/\/github.com\/SwiftyJSON\/SwiftyJSON<\/a><br \/>\n&nbsp;<br \/>\nCette classe JSON s&rsquo;utilise de la fa\u00e7on suivante:<\/p>\n<pre class=\"lang:swift mark:8-9 decode:true \">   func testerJSON(){\n        println(\"func testerJSON()\")\n        let film=\"star\"\n        let adresseURL = \"http:\/\/api.rottentomatoes.com\/api\/public\/v1.0\/movies.json?apikey=\\(CLE_API)&amp;q=\\(film)&amp;page_limit=\\(NB_FILMS)\"\n        let url = NSURL(string: adresseURL)\n        \/\/ Obtenir les donn\u00e9es en format brut et les convertir en JSON\n        let data = NSData(contentsOfURL:url!, options: nil, error: nil)\n        if let resultat = data {\n            println(\"L'URL a retourn\u00e9 des donn\u00e9es!\")\n            var error:NSError?\n            \/\/ Le plaisir commence ici:\n            let x = JSON(data: resultat, options: NSJSONReadingOptions.MutableContainers, error: &amp;error)\n            \/\/ et voil\u00e0!\n            println(x[\"movies\"][0][\"title\"])\n        } else\n        {\n            println(\"Erreur: l'URL n'a pas retourn\u00e9 de donn\u00e9es!\")\n        }\n    }  \/\/ func testerJSON()\n<\/pre>\n<p>&nbsp;<br \/>\nAutres exemples d&rsquo;utilisation:<\/p>\n<blockquote>\n<p style=\"color: #1d9421;\">\/\/ Obtenir le premier r\u00f4le du troixi\u00e8me acteur du premier film<br \/>\n<span style=\"color: #3d1d81;\">println<\/span><span style=\"color: #000000;\">(<\/span><span style=\"color: #539aa4;\">donneesJSON<\/span><span style=\"color: #000000;\">[<\/span>\u00ab\u00a0movies\u00a0\u00bb<span style=\"color: #000000;\">][<\/span><span style=\"color: #0435ff;\">0<\/span><span style=\"color: #000000;\">][<\/span>\u00ab\u00a0abridged_cast\u00a0\u00bb<span style=\"color: #000000;\">][<\/span><span style=\"color: #0435ff;\">2<\/span><span style=\"color: #000000;\">][<\/span>\u00ab\u00a0characters\u00a0\u00bb<span style=\"color: #000000;\">][<\/span><span style=\"color: #0435ff;\">0<\/span><span style=\"color: #000000;\">])<\/span><\/p>\n<p>\/\/Extraire un \u00e9l\u00e9ment de type Array:<br \/>\n<span style=\"color: #c32275;\">let<\/span><span style=\"color: #000000;\"> films = <\/span>donneesJSON<span style=\"color: #000000;\">[<\/span><span style=\"color: #c91b13;\">\u00ab\u00a0movies\u00a0\u00bb<\/span><span style=\"color: #000000;\">].<\/span>arrayValue<br \/>\n\/\/Boucler sur les \u00e9l\u00e9ments du tableau<br \/>\n<span style=\"color: #c32275;\">if<\/span> <span style=\"color: #c32275;\">let<\/span> films = <span style=\"color: #539aa4;\">donneesJSON<\/span>[<span style=\"color: #c91b13;\">\u00ab\u00a0movies\u00a0\u00bb<\/span>].<span style=\"color: #539aa4;\">arrayValue<\/span> {<br \/>\n<span style=\"color: #c32275;\">\u00a0 for<\/span> film <span style=\"color: #c32275;\">in<\/span> films { &#8230; }<\/p><\/blockquote>\n<p>&nbsp;<br \/>\nLa fa\u00e7on la plus simple de la rendre la classe JSON disponible dans un projet Swift est d&rsquo;ajouter les fichiers &lsquo;SwiftyJSON.swift&rsquo; et &lsquo;SwiftyJSON.h&rsquo; au projet.<br \/>\n<span style=\"color: #ff0000;\"><strong>Action &#8211; \u00c0\u00a0faire en lab:<\/strong><\/span><br \/>\nEn utilisant la\u00a0classe JSON, il faut afficher le titre et le nom des acteurs de tous les films:<br \/>\nPar exemple,<\/p>\n<pre class=\"lang:swift decode:true\">-------------------------------\nFilm: Star Wars: Episode III - Revenge of the Sith 3D\n\tActeur: Ewan McGregor\n\tActeur: Natalie Portman\n\tActeur: Hayden Christensen\n\tActeur: Ian McDiarmid\n\tActeur: Samuel L. Jackson\n-------------------------------\nFilm: Star\n\tActeur: Kumar Gaurav\n\tActeur: Rati Agnihotri\n\tActeur: Saeed Jaffrey\n\tActeur: Raj Kiran\n\tActeur: A.K. Hangal\n-------------------------------\nFilm: Star Trek Into Darkness\n\tActeur: Chris Pine\n\tActeur: Zachary Quinto\n\tActeur: Zoe Saldana\n\tActeur: Karl Urban\n\tActeur: Simon Pegg\n<\/pre>\n<p>&nbsp;<br \/>\n&nbsp;<\/p>\n<hr \/>\n<h1>Autres APIs<\/h1>\n<p>&nbsp;<br \/>\nVoici une liste d&rsquo;APIs disponibles via le web:<br \/>\n&nbsp;<\/p>\n<h2>R\u00e9pertoire d&rsquo;APIs web<\/h2>\n<p><a href=\"http:\/\/www.programmableweb.com\/apis\/directory\">http:\/\/www.programmableweb.com\/apis\/directory<\/a><br \/>\n&nbsp;<\/p>\n<h2>M\u00e9t\u00e9o sur Yahoo<\/h2>\n<p><a href=\"http:\/\/query.yahooapis.com\/v1\/public\/yql?q=select%20item%20from%20weather.forecast%20where%20location%3D%22CAXX0301%22&amp;format=json\">http:\/\/query.yahooapis.com\/v1\/public\/yql?q=select%20item%20from%20weather.forecast%20where%20location%3D%22<span style=\"color: #ff0000;\">CAXX0301<\/span>%22&amp;format=json<\/a><br \/>\nCe qui donne la m\u00e9t\u00e9o pour Montr\u00e9al (CAXX0301)<br \/>\nVoir: \u00a0<a href=\"http:\/\/developer.yahoo.com\/yql\/\">http:\/\/developer.yahoo.com\/yql\/<\/a><\/p>\n<h2><\/h2>\n<h2>Trouvez le UID d&rsquo;une ville<\/h2>\n<p><a href=\"http:\/\/wxdata.weather.com\/wxdata\/search\/search?where=montr\">http:\/\/wxdata.weather.com\/wxdata\/search\/search?where=montr<\/a><br \/>\n&nbsp;<\/p>\n<h2>Cotes de la bourse sur Yahoo<\/h2>\n<p><a href=\"http:\/\/query.yahooapis.com\/v1\/public\/yql?q=select%20%2a%20from%20yahoo.finance.quotes%20where%20symbol%20in%20%28%22YHOO%22%2C%22AAPL%22%2C%22GOOG%22%2C%22MSFT%22%29%0A%09%09&amp;env=http%3A%2F%2Fdatatables.org%2Falltables.env&amp;format=json\">http:\/\/query.yahooapis.com\/v1\/public\/yql?q=select%20%2a%20from%20yahoo.finance.quotes%20where%20symbol%20in%20%28%22<span style=\"color: #ff0000;\">YHOO<\/span>%22%2C%22<span style=\"color: #ff0000;\">AAPL<\/span>%22%2C%22<span style=\"color: #ff0000;\">GOOG<\/span>%22%2C%22<span style=\"color: #ff0000;\">MSFT<\/span>%22%29%0A%09%09&amp;env=http%3A%2F%2Fdatatables.org%2Falltables.env&amp;format=json<\/a><br \/>\n<strong>Ce qui donne les cotes de Yahoo, \u00a0d&rsquo;Apple et d&rsquo;Amazon et de microsoft.<\/strong><\/p>\n<h2><\/h2>\n<h2>Les taux de change<\/h2>\n<p><a href=\"http:\/\/finance.yahoo.com\/webservice\/v1\/symbols\/allcurrencies\/quote?format=json\">http:\/\/finance.yahoo.com\/webservice\/v1\/symbols\/allcurrencies\/quote?format=json<\/a><\/p>\n<h2><\/h2>\n<h2>tou.tv<\/h2>\n<p><a href=\"http:\/\/api.tou.tv\/v1\/toutvapiservice.svc\/json\/GetPageRepertoire\">http:\/\/api.tou.tv\/v1\/toutvapiservice.svc\/json\/GetPageRepertoire<\/a><br \/>\nCe qui donne le r\u00e9pertoire de tou.tv<br \/>\nVoir: \u00a0<a href=\"https:\/\/code.google.com\/p\/tou-tv-for-boxee\/wiki\/Api\">https:\/\/code.google.com\/p\/tou-tv-for-boxee\/wiki\/Api<\/a><br \/>\n&nbsp;<\/p>\n<h2>API Apple (iTune, app store, &#8230;)<\/h2>\n<p><a href=\"http:\/\/www.apple.com\/itunes\/affiliates\/resources\/documentation\/itunes-store-web-service-search-api.html\">http:\/\/www.apple.com\/itunes\/affiliates\/resources\/documentation\/itunes-store-web-service-search-api.html<\/a><br \/>\n&nbsp;<\/p>\n<h2>GiantBomb (jeux)<\/h2>\n<p><a href=\"http:\/\/www.giantbomb.com\/api\/\">http:\/\/www.giantbomb.com\/api\/<\/a><\/p>\n<hr \/>\n<p>Note: \u00a0L&rsquo;image sur cette page est la propri\u00e9t\u00e9 intellectuelle de\u00a0Flixster.<br \/>\n&nbsp;<\/p>\n<p style=\"text-align: right;\"><strong><span style=\"color: #003366;\">Document par Alain Boudreault (c) 2013-2015 &#8211; r\u00e9vision du 2015.10.16 (pour Xcode 6.4)<\/span>\u00a0<\/strong><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Utilisation d&rsquo;une &lsquo;API&rsquo; web R\u00e9vision du 2015.11.16 &#8211; conversion vers Xcode 6.4 Dans le tutoriel\u00a0TIMFlix, nous avons construit une application qui affichait une liste de vid\u00e9os \u00e0 l&rsquo;int\u00e9rieur d&rsquo;un UITableView. Les informations des vid\u00e9os, ainsi que l&rsquo;image des affiches, \u00e9taient renseign\u00e9es localement grace \u00e0 un fichier de propri\u00e9t\u00e9s. L&rsquo;inconv\u00e9nient de cette approche est \u00e9vident lorsque [&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-1656","page","type-page","status-publish","hentry"],"_links":{"self":[{"href":"https:\/\/ve2cuy.com\/xcode\/wp-json\/wp\/v2\/pages\/1656","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=1656"}],"version-history":[{"count":0,"href":"https:\/\/ve2cuy.com\/xcode\/wp-json\/wp\/v2\/pages\/1656\/revisions"}],"wp:attachment":[{"href":"https:\/\/ve2cuy.com\/xcode\/wp-json\/wp\/v2\/media?parent=1656"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}