{"id":2938,"date":"2016-10-18T13:12:49","date_gmt":"2016-10-18T17:12:49","guid":{"rendered":"\/cours\/xcode\/wp\/?page_id=2938"},"modified":"2016-10-18T13:12:49","modified_gmt":"2016-10-18T17:12:49","slug":"tim-ze-games","status":"publish","type":"page","link":"https:\/\/ve2cuy.com\/xcode\/tim-ze-games\/","title":{"rendered":"TIM.Ze.Games"},"content":{"rendered":"<h1>Utilisation d&rsquo;une &lsquo;API&rsquo; web<\/h1>\n<p><strong><span style=\"color: #339966;\">R\u00e9vision du 2017.01.04 &#8211; conversion vers Xcode\u00a08.0 et utilisation de Alamofire\u00a0<\/span><\/strong><br \/>\nDans le tutoriel\u00a0<a href=\"\/xcode\/index.php\/labo\/timflix-delegation-et-uitableview-personnalisee\/\">TIMFlix<\/a>\u00a0ou &lsquo;<a href=\"\/xcode\/index.php\/les-amis-de-la-science\/\">Les Amis de la science<\/a>\u00ab\u00a0, 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>\u00c9l\u00e9ments de contenu<\/h1>\n<ul>\n<li>Utiliser ad\u00e9quatement NSArray(fromURL:) as? \u00a0Array&lt;Dictionary&lt;String, Any&gt;&gt;.<\/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:\/\/prof-tim.cstj.qc.ca\/cours\/xcode\/sources\/timgames\/api.timgames.php\">API-TIM.Ze.Game<\/a>.<\/li>\n<li>Programmer des traitements non bloquants pour une application.<\/li>\n<\/ul>\n<p><a href=\"\/xcode\/wp-content\/uploads\/2016\/10\/Chameleon-1.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignleft wp-image-2947 size-full\" src=\"\/xcode\/wp-content\/uploads\/2016\/10\/Chameleon-1.png\" alt=\"Chameleon-1\" width=\"200\" height=\"147\" \/><\/a><br \/>\n<strong>Pr\u00e9-requis:<\/strong><br \/>\nAvoir compl\u00e9t\u00e9 le tutoriel\u00a0<a href=\"\/xcode\/index.php\/labo\/timflix-delegation-et-uitableview-personnalisee\/\">TIMFlix<\/a>\u00a0ou bien le laboratoire &lsquo;<a href=\"\/xcode\/index.php\/les-amis-de-la-science\/\">Les amis de la science<\/a>&lsquo;, ou bien avoir une maitrise de l&rsquo;objet UITableView + segue + passage de param\u00e8tres entre les sc\u00e8nes d&rsquo;une app.<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\/XnILt8LieI4?feature=oembed\" frameborder=\"0\" allowfullscreen><\/iframe><\/p>\n<hr \/>\n<h1>Partie 1 &#8211; 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\u00a0<span style=\"color: #003366;\"><strong>SGBD<\/strong><\/span>\u00a0(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\u00a0<span style=\"color: #003366;\"><strong><span style=\"text-decoration: underline;\">scripts de type &lsquo;serveur web&rsquo; de traitements<\/span><\/strong><\/span>\u00a0et\u00a0<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\u00a0<span style=\"color: #003366;\"><strong>PHP<\/strong><\/span>,\u00a0<span style=\"color: #003366;\"><strong>ASP<\/strong><\/span>,\u00a0<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\u00a0<span style=\"color: #003366;\"><strong>curl()<\/strong><\/span>,\u00a0<span style=\"color: #003366;\"><strong>NSArray(URL:)<\/strong><\/span>\u00a0et autres.<br \/>\nVoir la d\u00e9finition de\u00a0<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>,\u00a0<strong>XML<\/strong>,\u00a0<strong>JSON<\/strong>,\u00a0<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\u00bbHiv17&Prime;<br \/>\n\u00ab\u00a0Gameloft\u00a0\u00bb,\u00a0\u00bb1&Prime;,\u00a0\u00bbHiv17&Prime;<\/p><\/blockquote>\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>\u00a0).<br \/>\nDans le cadre d&rsquo;apprentissages, une solution comme\u00a0<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>\u00a0&#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<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><span style=\"color: #ff0000;\"><strong>API.TIM.03<\/strong><\/span>\u00a0&#8211; L&rsquo;API retournera le r\u00e9sultat texte suivant:<\/p>\n<blockquote><p>clef = nom_ajout, valeur = Alain<br \/>\nclef = created_at, valeur = 2014-11-01 05:11:43<br \/>\nclef = categorie, valeur = 3<br \/>\nclef = adresse_ip, valeur = 24.200.185.163<br \/>\nclef = pensee_texte, valeur = Il etait une fois un gars &#8230;<br \/>\nclef = pensee_auteur, valeur = Moi<br \/>\nclef = pensee_lien_image, valeur = http:\/\/www.imagesdoc.com\/var\/bayard\/storage\/images\/smk\/images-doc\/images\/images-doc-plus\/que-vois-tu\/photo-mystere-2-image-3\/24513202-1-fre-FR\/Photo-mystere-2-Image-3.jpg<\/p><\/blockquote>\n<p><a href=\"http:\/\/prof-tim.cstj.qc.ca\/cours\/xcode\/sources\/apitim.php\">\u00a0lien de test<\/a><br \/>\n<span style=\"color: #ff0000;\"><strong>API.TIM.04<\/strong><\/span>\u00a0&#8211; Voici un script PHP qui retourne le r\u00e9sultat en format &lsquo;plist&rsquo;:<\/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-2016 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><span style=\"color: #008080;\"><strong>Note<\/strong><\/span>: Voir la structure d&rsquo;un fichier &lsquo;plist&rsquo; sous Xcode:<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 2016-11-02 09:11:55 --&gt;\n&lt;!-- (c) 2014-2016 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=\"http:\/\/prof-tim.cstj.qc.ca\/cours\/xcode\/sources\/apitim.php?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 2016.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><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 2016.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=\"http:\/\/prof-tim.cstj.qc.ca\/cours\/xcode\/sources\/apitim.php?mode=rnd&amp;quant=2&amp;format=json\">lien de test<\/a><br \/>\nExemple php complet:<\/p>\n<pre class=\"lang:php decode:true \">&lt;?php\n\/\/ Fichier:      apitim.php\n\/\/ Par:          Alain Boudreault\n\/\/ Date:         2016.10.23\n\/\/ Description:\n\/\/ -------------------------------------------------------------\n$servername = \"localhost\";\n$username   = \"votreAcces\";\n$password   = \"votreMotDePasse\";\n$dbname     = \"votreBD\";\n$mode   = isset($_GET[\"mode\"]) ? $_GET[\"mode\"] : \"all\";\n$quant  = isset($_GET[\"quant\"]) ? $_GET[\"quant\"] : \"2\";\n$format = isset($_GET[\"format\"]) ? $_GET[\"format\"] : \"texte\";\n\/\/ Create connection\n$conn = new mysqli($servername, $username, $password, $dbname);\n\/\/ Check connection\nif ($conn-&gt;connect_error) {\n    die(\"Connection failed: \" . $conn-&gt;connect_error);\n}\n$sql = \"SELECT `nom_ajout` ,  `created_at`, `categorie`, `adresse_ip` , `pensee_texte`,  `pensee_auteur`,  `pensee_lien_image`  FROM penseesdujours\";\nif ($mode == \"all\") {\n    $sql = \"SELECT `nom_ajout` ,  `created_at`, `categorie`, `adresse_ip` , `pensee_texte`,  `pensee_auteur`,  `pensee_lien_image` FROM penseesdujours\";\n}  \/\/ mode=all\nif ($mode == \"rnd\") {\n    $sql = \"SELECT `nom_ajout` ,  `created_at`,`categorie`, `adresse_ip` , `pensee_texte`,  `pensee_auteur`,  `pensee_lien_image` FROM penseesdujours ORDER BY RAND() LIMIT $quant\";\n} \/\/ mode=rnd\nif ($mode == \"adulte\") {\n    $sql = \"SELECT * FROM (SELECT `categorie`,`nom_ajout`, `created_at`, `adresse_ip`, `pensee_texte`, \" .\n\t\" `pensee_auteur`, `pensee_lien_image` FROM penseesdujours where categorie = 3) as tmp ORDER BY RAND() LIMIT $quant\";\n    echo $sql . \"\\n\\n\";\n} \/\/ mode=adulte\n$res = $conn-&gt;query($sql);\n\/\/ En format plist\nif ($format == \"plist\") {\n  echo '&lt;?xml version=\"1.0\" encoding=\"UTF-8\"?&gt;'.\"\\n\";\n  echo '&lt;!DOCTYPE plist PUBLIC \"-\/\/Apple\/\/DTD PLIST 1.0\/\/EN\" \"http:\/\/www.apple.com\/DTDs\/PropertyList-1.0.dtd\"&gt;'.\"\\n\";\n  echo '&lt;plist version=\"1.0\"&gt;'.\"\\n\";\n  echo \"&lt;!-- Liste g\u00e9n\u00e9r\u00e9e par l'API TIM le \".date('Y-m-d h:m:s').\" --&gt;\\n\";\n  echo \"&lt;!-- (c) 2014-2016 par Alain Boudreault --&gt;\\n\";\n  echo \"&lt;array&gt;\\n\";\n  while($r = $res-&gt;fetch_assoc()) {\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\n  echo \"&lt;\/array&gt;\\n&lt;\/plist&gt;\";\n} \/\/ format = plist\n\/\/ En format texte\nif ($format == \"texte\") {\n  \/\/ Liste simple\n  while($row = $res-&gt;fetch_assoc()) {\n    foreach ($row as $key =&gt; $value) {\n       echo \"clef = \".$key.\", valeur = \".$value.\"&lt;br&gt;\\n\";\n     } \/\/ foreach\n  } \/\/ while\n} \/\/ if format == texte\n\/\/ En format json\nif ($format == \"json\") {\n  \/\/ tableau du r\u00e9sultat final\n  $resultat = array();\n  $resultat['info'] = array(\"API_TIM\" =&gt; \"version 2016.10.01\", \"type_requete\" =&gt; \"json\");\n  while($r = $res-&gt;fetch_assoc()) {\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\n  echo json_encode($resultat, JSON_PRETTY_PRINT);\n} \/\/ if format == json\n$conn-&gt;close();\n\/\/   echo phpinfo();\n?&gt;<\/pre>\n<hr \/>\n<h1>Partie 2 &#8211; Utilisation de l&rsquo;API de Yahoo finance<\/h1>\n<p>\u00c9tant donn\u00e9 le lien suivant:<br \/>\n<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\">Obtenir cotes de la bourse<\/a><br \/>\nNous obtenons la structure suivante:<\/p>\n<pre class=\"lang:default decode:true \">{\n    \"query\":{  \/\/ Dictionary&lt;String, Any&gt;\n             \"count\":4,\n             \"created\":\"2016-11-01T15:53:16Z\",\n             \"lang\":\"fr-ca\",\n             \"results\": {  \/\/ Dictionary&lt;String, Any&gt;\n                  \/\/ *** Tableau des cotes\n\t\t  \"quote\":[ \/\/ Array&lt;Dictionary&lt;String, Any&gt;&gt;\n\t\t    \/\/ ****  Premier \u00e9l\u00e9ment\n\t          {     \"symbol\":\"YHOO\",\n   \t                \"Ask\":\"40.89\",\n     \t\t        \"AverageDailyVolume\":\"10498500\",\n        \t        \"Bid\":\"40.86\",\n          \t        \"AskRealtime\":null,\n                    \"BidRealtime\":null,\n                    \"BookValue\":\"36.39\",\n                    \"Change_PercentChange\":\"-0.23 - -0.55%\",\n                    \"Change\":\"-0.23\",\n                    \"Commission\":null,\n                    \"Currency\":\"USD\",\n                    \"ChangeRealtime\":null,\n                    \"AfterHoursChangeRealtime\":null,\n                    \"DividendShare\":null,\n                    \"LastTradeDate\":\"10\/31\/2016\",\n                    \"TradeDate\":null,\n                    \"EarningsShare\":\"-5.11\",\n                    \"ErrorIndicationreturnedforsymbolchangedinvalid\":null,\n                    \"EPSEstimateCurrentYear\":\"0.58\",\n                    \"EPSEstimateNextYear\":\"0.62\",\n                    \"EPSEstimateNextQuarter\":\"0.14\",\n                    \"DaysLow\":null,\n                    \"DaysHigh\":null,\n                    \"YearLow\":\"26.15\",\n                    \"YearHigh\":\"44.92\",\n                    \"HoldingsGainPercent\":null,\n                    \"AnnualizedGain\":null,\n                    \"HoldingsGain\":null,\n                    \"HoldingsGainPercentRealtime\":null,\n                    \"HoldingsGainRealtime\":null,\n                    \"MoreInfo\":null,\n                    \"OrderBookRealtime\":null,\n                    \"MarketCapitalization\":\"39.78B\",\n                    \"MarketCapRealtime\":null,\n                    \"EBITDA\":\"90.38M\",\n                    \"ChangeFromYearLow\":\"15.40\",\n                    \"PercentChangeFromYearLow\":\"+58.89%\",\n                    \"LastTradeRealtimeWithTime\":null,\n                    \"ChangePercentRealtime\":null,\n                    \"ChangeFromYearHigh\":\"-3.37\",\n                    \"PercebtChangeFromYearHigh\":\"-7.50%\",\n                    \"LastTradeWithTime\":\"4:00pm - &lt;b&gt;41.55&lt;\/b&gt;\",\n                    \"LastTradePriceOnly\":\"41.55\",\n                    \"HighLimit\":null,\n                    \"LowLimit\":null,\n                    \"DaysRange\":null,\n                    \"DaysRangeRealtime\":null,\n                    \"FiftydayMovingAverage\":\"42.83\",\n                    \"TwoHundreddayMovingAverage\":\"39.65\",\n                    \"ChangeFromTwoHundreddayMovingAverage\":\"1.90\",\n                    \"PercentChangeFromTwoHundreddayMovingAverage\":\"+4.78%\",\n                    \"ChangeFromFiftydayMovingAverage\":\"-1.28\",\n                    \"PercentChangeFromFiftydayMovingAverage\":\"-2.98%\",\n                    \"Name\":\"Yahoo! Inc.\",\n                    \"Notes\":null,\n                    \"Open\":null,\n                    \"PreviousClose\":\"41.78\",\n                    \"PricePaid\":null,\n                    \"ChangeinPercent\":\"-0.55%\",\n                    \"PriceSales\":\"8.04\",\n                    \"PriceBook\":\"1.15\",\n                    \"ExDividendDate\":null,\n                    \"PERatio\":null,\n                    \"DividendPayDate\":null,\n                    \"PERatioRealtime\":null,\n                    \"PEGRatio\":\"-124.19\",\n                    \"PriceEPSEstimateCurrentYear\":\"71.64\",\n                    \"PriceEPSEstimateNextYear\":\"67.02\",\n                    \"Symbol\":\"YHOO\",\n                    \"SharesOwned\":null,\n                    \"ShortRatio\":\"4.25\",\n                    \"LastTradeTime\":\"4:00pm\",\n                    \"TickerTrend\":null,\n                    \"OneyrTargetPrice\":\"45.14\",\n                    \"Volume\":\"10108\",\n                    \"HoldingsValue\":null,\n                    \"HoldingsValueRealtime\":null,\n                    \"YearRange\":\"26.15 - 44.92\",\n                    \"DaysValueChange\":null,\n                    \"DaysValueChangeRealtime\":null,\n                    \"StockExchange\":\"NMS\",\n                    \"DividendYield\":null,\n                    \"PercentChange\":\"-0.55%\"},\n                    \/\/ *** Deuxi\u00e8me \u00e9l\u00e9ment\n                    {\"symbol\":\"AAPL\",\"Ask\":\"113.60\", ... }\n\t\t] \/\/ **** Fin du tableau des cotes\n\t   }  \/\/ results\n     } \/\/ query\n}<\/pre>\n<p>&nbsp;<\/p>\n<hr \/>\n<p><span style=\"color: #ff0000;\"><strong>Action<\/strong><\/span>\u00a0<span style=\"color: #ff0000;\"><strong>API.TIM.01<\/strong><\/span>\u00a0&#8211; <span style=\"color: #008080;\"><strong>Dans un nouveau projet<\/strong><\/span>, ajoutons le code suivant:<\/p>\n<pre class=\"lang:swift decode:true\">\/\/  ViewController.swift\n\/\/  Ajouter ceci dans le fichier info.plist\n\/*\n &lt;key&gt;NSAppTransportSecurity&lt;\/key&gt;\n &lt;dict&gt;\n &lt;key&gt;NSAllowsArbitraryLoads&lt;\/key&gt;\n &lt;true\/&gt;\n &lt;\/dict&gt;\n *\/\nimport UIKit\nclass ViewController: UIViewController {\n    \/\/ let URLYahooFinance = \"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\"\n    \/\/ requete = http:\/\/query.yahooapis.com\/v1\/public\/yql?q=select * from yahoo.finance.quotes where symbol in (\"MSFT\",\"FB\",\"INTC\",\"HPQ\",\"AAPL\",\"AMD\",\"COKE\")&amp;env=http:\/datatables.org\/alltables.env&amp;format=json\n    private var dic_resultats  = Dictionary&lt;String, Any&gt;()\n    private var _listeDesItems = Array&lt;Dictionary&lt;String, Any&gt;&gt;()\n    \/\/ URL vers l'API finance de Yahoo\n    let YahooFinanceURLpart1    = \"http:\/\/query.yahooapis.com\/v1\/public\/yql?q=\"\n    let requeteSQL              = \"select * from yahoo.finance.quotes where symbol in (\"\n    let porteFeuille = \"\\\"MSFT\\\",\\\"FB\\\",\\\"INTC\\\",\\\"HPQ\\\",\\\"AAPL\\\",\\\"AMD\\\",\\\"COKE\\\"\"\n    let YahooFinanceURLpart2    = \")&amp;env=http:\/\/datatables.org\/alltables.env&amp;format=json\"\n    var URLYahooFinance         = \"\"\n    func obtenirLesDonn\u00e9es(_ url:String) {\n        let uneURL = URL(string: url)!  \/\/Danger!\n        \/\/\/ Ex\u00e9cuter le traitement suivant en parall\u00e8le\n        \/\/\/ DispatchQueue.main.async ( execute: {\n        if let _donn\u00e9es = NSData(contentsOf: uneURL) as? Data {\n            do {\n                let json = try JSONSerialization.jsonObject(with: _donn\u00e9es, options: JSONSerialization.ReadingOptions()) as? Dictionary&lt;String, Dictionary&lt;String, Any&gt;&gt;\n                print(\"Conversion JSON r\u00e9ussie\")\n                self.dic_resultats = json!\n                \/\/print(self.dic_resultats)\n                \/\/ Cr\u00e9er un tableau \u00e0 partir du champ 'resultats'\n                if let listeDesItems = ((self.dic_resultats[\"query\"] as? Dictionary&lt;String, Any&gt;)?[\"results\"]as? Dictionary&lt;String, Any&gt;)?[\"quote\"] as? Array&lt;Dictionary&lt;String, Any&gt;&gt; {\n                    self._listeDesItems = listeDesItems\n                    print(\"Liste des items:\\n\\(self._listeDesItems)\")\n                    \/\/ self.collectionDesItems.reloadData()\n                }\n                \/\/ print(json)\n            } catch {\n                print(\"\\n\\n#Erreur: Probl\u00e8me de conversion json:\\(error)\\n\\n\")\n            } \/\/ do\/try\/catch\n        } else\n        {\n            print(\"\\n\\n#Erreur: impossible de lire les donn\u00e9es via:\\(self.URLYahooFinance)\\n\\n\")\n        } \/\/ if let _donn\u00e9es = NSData\n        \/\/\/ }) \/\/ DispatchQueue.main.async\n    } \/\/ obtenirLesDonn\u00e9es(_ url:String)\n    override func viewDidLoad() {\n        super.viewDidLoad()\n        \/\/ Construire l'URL de l'API Yahoo \u00e0 partir du portefeuille local\n        URLYahooFinance = YahooFinanceURLpart1 + (requeteSQL + porteFeuille).addingPercentEncoding(withAllowedCharacters: CharacterSet.alphanumerics)! + YahooFinanceURLpart2\n        print(URLYahooFinance)\n        obtenirLesDonn\u00e9es(URLYahooFinance)\n    } \/\/ viewDidLoad()\n}<\/pre>\n<p>Analyse du code pr\u00e9c\u00e9dent:<br \/>\n<span style=\"color: #ff0000;\"><strong>Action<\/strong><\/span>: Testons l&rsquo;application<br \/>\n<strong>R\u00e9sultat obtenu:<\/strong><\/p>\n<pre class=\"lang:swift decode:true\">2016-11-05 09:40:54.698663 Tester Yahoo finance[8399:131637] [] tcp_connection_get_statistics DNS: 3ms\/9ms since start, TCP: 88ms\/103ms since start, TLS: 0ms\/0ms since start\nConversion JSON r\u00e9ussie\nListe des items:\n[[\"Change_PercentChange\": -0.50 - -0.84%, \"EPSEstimateCurrentYear\": 2.97, \"LastTradePriceOnly\": 58.71, \"ChangePercentRealtime\": &lt;null&gt;, \"Open\": 58.65, \"HoldingsGainRealtime\": &lt;null&gt;, \"DaysLow\": 58.52, \"PERatio\": 28.12, \"PERatioRealtime\": &lt;null&gt;, \"OneyrTargetPrice\": 63.81, \"FiftydayMovingAverage\": 58.21, \"AskRealtime\": &lt;null&gt;, \"SharesOwned\": &lt;null&gt;, \"DaysHigh\": 59.28, \"Name\": Microsoft Corporation, \"Change\": -0.50, \"DividendYield\": 2.62, \"YearHigh\": 61.37, \"DividendPayDate\": 12\/8\/2016, \"YearRange\": 48.04 - 61.37,\n...<\/pre>\n<h3><span style=\"color: #ff0000;\"><strong>Action API.TIM.02<\/strong><\/span>\u00a0&#8211; \u00a0Affichons le nom de l&rsquo;action ainsi que\u00a0le\u00a0prix demand\u00e9:<\/h3>\n<pre class=\"lang:swift decode:true\">    func afficherActions() {\n        print(\"---------------------------------------\")\n        for action in _listeDesItems{\n            if let _nom = action[\"Name\"], let _prix = action[\"Ask\"] {\n                print(\"Action: \\(_nom), prix: \\(_prix)\")\n            }\n        } \/\/ for action in\n        print(\"---------------------------------------\")\n    } \/\/ afficherActions()\n<\/pre>\n<p>R\u00e9sultat obtenu:<\/p>\n<pre class=\"lang:swift decode:true \">---------------------------------------\nAction: Microsoft Corporation, prix: 58.74\nAction: Facebook, Inc., prix: 120.72\nAction: Intel Corporation, prix: 34.12\nAction: HP Inc. Common Stock, prix: 14.71\nAction: Apple Inc., prix: 108.85\nAction: Advanced Micro Devices, Inc., prix: 6.57\nAction: Coca-Cola Bottling Co. Consolid, prix: &lt;null&gt;\n---------------------------------------<\/pre>\n<p>Et pour une lecture des donn\u00e9es \u00e0 chaque n sec:<\/p>\n<pre class=\"lang:swift decode:true\">    func viewDidLoad() {\n    ...\n        Timer.scheduledTimer(timeInterval: 10, target: self, selector: #selector(self.doTimer), userInfo: nil, repeats: true)\n    } \/\/ viewDidLoad()\n    func doTimer(){\n        obtenirLesDonn\u00e9es(URLYahooFinance)\n        afficherActions()\n        \/\/\/  Actualiser une collectionView\n        \/\/\/  tableViewActions.reloadData()\n    }\n<\/pre>\n<hr \/>\n<h1>Ex\u00e9cution d&rsquo;une requ\u00eate en parall\u00e8le avec l&rsquo;application:<\/h1>\n<pre class=\"lang:swift decode:true\">\/\/ Retirer le commentaire des lignes suivantes:\n  DispatchQueue.main.async ( execute: {\n  ...\n }) \/\/ DispatchQueue.main.async\n<\/pre>\n<p>Analysons le r\u00e9sultat suivant:<\/p>\n<pre class=\"lang:swift decode:true \">http:\/\/query.yahooapis.com\/v1\/public\/yql?q=select%20%2A%20from%20yahoo%2Efinance%2Equotes%20where%20symbol%20in%20%28%22MSFT%22%2C%22FB%22%2C%22INTC%22%2C%22HPQ%22%2C%22AAPL%22%2C%22AMD%22%2C%22COKE%22)&amp;env=http:\/\/datatables.org\/alltables.env&amp;format=json\n---------------------------------------\n---------------------------------------\n2016-11-05 10:23:11.400069 Tester Yahoo finance[11698:169904] subsystem: com.apple.BackBoardServices.fence, ca<\/pre>\n<p>La liste est vide la premi\u00e8re fois.<br \/>\n<span style=\"color: #008080;\"><strong>Raison<\/strong><\/span>:\u00a0Nous affichons le contenu du tableau avant d&rsquo;avoir re\u00e7u la r\u00e9ponse de l&rsquo;API.<br \/>\nPr\u00e9c\u00e9demment, l&rsquo;ex\u00e9cution du programme bloquait \u00e0 la lecture des donn\u00e9es \u00e0 partir d&rsquo;Internet.<br \/>\nMaintenant, avec &lsquo;\u00a0<span style=\"color: #008080;\"><strong>DispatchQueue.main.async ( execute:\u00a0&lsquo;,\u00a0<\/strong><\/span>la lecture des donn\u00e9es est faite en arri\u00e8re plan et notre programme principal continu les traitements.<\/p>\n<pre class=\"lang:swift decode:true\">obtenirLesDonn\u00e9es(URLYahooFinance)  \/\/ Envoy\u00e9 en arri\u00e8re plan\nafficherActions()                   \/\/ *** N'attend plus apr\u00e8s l'instruction pr\u00e9c\u00e9dente.<\/pre>\n<p>Avec cette technique, il faut traiter l&rsquo;affichage des donn\u00e9es et l&rsquo;actualisation des composants MVC \u00e0 l&rsquo;int\u00e9rieur du bloc de code (inline function, fonction anonyme).<br \/>\nDans ce cas, les variables doivent-\u00eatre pr\u00e9c\u00e9d\u00e9es de &lsquo;self&rsquo;; self.monCollectionView.reloadData().<br \/>\nVoir le code de la solution:<br \/>\n<a href=\"https:\/\/bitbucket.org\/alain_boudreault\/lecture-de-api-yahoo-finance\/get\/c230d1c1db6f.zip\">T\u00e9l\u00e9charger la solution<\/a><\/p>\n<hr \/>\n<h1><span style=\"color: #ff0000;\">Laboratoire<\/span><\/h1>\n<h3><span style=\"color: #666699;\">Choix 1 &#8211; Valeurs de conversion des devises en fonction du dollar am\u00e9ricain.<\/span><\/h3>\n<p>Obtenir la valeur des monnaies en fonction de USD \u00e0 partir de l&rsquo;API suivante:<br \/>\n<span style=\"color: #ff0000;\"><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><\/span><br \/>\n<span style=\"color: #ff0000;\"><strong>Action<\/strong><\/span>: \u00c9crire une application qui affiche, dans un UITableView, le Code (symbol) des devises ainsi que le prix (price). \u00a0Actualiser les donn\u00e9es \u00e0 chaque 15\u00a0secondes.<br \/>\n&nbsp;<\/p>\n<h3><span style=\"color: #666699;\">Choix 2 (d\u00e9fi plus \u00e9lev\u00e9)\u00a0&#8211; La temp\u00e9rature en temp r\u00e9el de 10 villes\u00a0<\/span><\/h3>\n<p>Obtenir la temp\u00e9rature\u00a0\u00e0 partir de l&rsquo;API suivante:<br \/>\n<a href=\"https:\/\/query.yahooapis.com\/v1\/public\/yql?q=select%20*%0Afrom%20weather.forecast%0Awhere%20woeid%20in%20(3534%2C3518%2C3444%2C615702%2C2459115%2C742676%2C1118370%2C44418%2C212226%2C2151443)%0Aand%20u%20%3D%20'C'%3B&amp;format=json&amp;diagnostics=true&amp;callback=\">Temp\u00e9rature de 10 villes<\/a><br \/>\n<span style=\"color: #ff0000;\"><strong>Action<\/strong><\/span>: \u00c9crire une application qui affiche, dans un UITableView, le nom de la ville\u00a0ainsi que la temp\u00e9rature actuelle. \u00a0Actualiser les donn\u00e9es \u00e0 chaque 15\u00a0secondes.<\/p>\n<hr \/>\n<h1>Partie 3 &#8211; API\u00a0TIM.Ze.Game<\/h1>\n<p>Le site &lsquo;TIM.Ze.Game&rsquo; propose une API d&rsquo;acc\u00e8s aux donn\u00e9es qu&rsquo;il compile. \u00a0Ces donn\u00e9es nous renseignent sur des pochettes de jeux, \u00a0les critiques, les suiveux, &#8230;<br \/>\nPour interroger l&rsquo;api, il suffit de suivre l&rsquo;URL suivante:<\/p>\n<blockquote><p>http:\/\/api-tim.ze.game?apikey=<span style=\"color: #ff0000;\">VOTRECLE<\/span>&amp;q=<span style=\"color: #ff0000;\">MODELE_DE_RECHERCHE<\/span>&amp;quant=<span style=\"color: #ff0000;\">NB_PAGES<\/span>&amp;format=json<\/p><\/blockquote>\n<p style=\"text-align: left;\">Comme par exemple:\u00a0<a href=\"http:\/\/prof-tim.cstj.qc.ca\/cours\/xcode\/sources\/timgames\/api.timgames.php?apikey=ceciEstUltraSecret&amp;q=star&amp;quant=50&amp;format=json\">http:\/\/prof-tim.cstj.qc.ca\/cours\/xcode\/sources\/timgames\/api.timgames.php?<strong><span style=\"color: #008080;\"><span style=\"color: #ff0000;\">apikey=<\/span>ceciEstUltraSecret&amp;<span style=\"color: #ff0000;\">q=<\/span>Star&amp;<span style=\"color: #ff0000;\">quant=<\/span>50&amp;<span style=\"color: #ff0000;\">format=<\/span>json<\/span><\/strong><\/a><\/p>\n<p>La requ\u00eate pr\u00e9c\u00e9dente devrait nous retourner une structure JSON contenant une liste de 50 pochettes\u00a0dont la cha\u00eene &lsquo;Star&rsquo; appara\u00eet dans le titre du jeu.<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:<br \/>\nif let <span style=\"color: #008080;\"><strong>NSData(contentsOf<\/strong><\/span>: uneURL) as? Data {<br \/>\ndo {<br \/>\nlet json = <span style=\"color: #008080;\"><strong>try JSONSerialization.jsonObject(with: _donn\u00e9es<\/strong><\/span>, options: JSONSerialization.ReadingOptions()) as? Dictionary&lt;String, Any&gt;<br \/>\n}<\/p>\n<hr \/>\n<h2>\u00c9tape 1 &#8211; Prise en main du projet de d\u00e9part &#8211; lecture des donn\u00e9es<\/h2>\n<p><span style=\"color: #ff0000;\"><strong>Action 1.1<\/strong><\/span>\u00a0&#8211; Ouvrons le projet\u00a0<a href=\"https:\/\/bitbucket.org\/alain_boudreault\/tim.ze.games-depart\/downloads?tab=downloads\">Projet &#8211; TIM.Ze.Game &#8211; depart<\/a>\u00a0et ex\u00e9cutons l&rsquo;application<br \/>\n<a href=\"\/xcode\/wp-content\/uploads\/2016\/10\/TIM.ze_.Game-cap30.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-2985\" src=\"\/xcode\/wp-content\/uploads\/2016\/10\/TIM.ze_.Game-cap30.png\" alt=\"TIM.ze.Game-cap30\" width=\"1894\" height=\"697\" \/><\/a><br \/>\n<span style=\"color: #ff0000;\"><strong>Action 1.1.2<\/strong><\/span>\u00a0&#8211; Examinons le code de la classe &lsquo;Intro&rsquo;; <span style=\"color: #008080;\"><strong>animations et trame sonore<\/strong><\/span>:<\/p>\n<pre class=\"lang:swift decode:true\">\/\/ Voici comment animer une propri\u00e9t\u00e9:\ntitre1.alpha  = 0\nUIView.animate(withDuration: 3.0,\n                      delay: 0.0,\n                    options: UIViewAnimationOptions.curveEaseInOut,\n                 animations: { self.titre1.alpha = 1.0 },\n                 completion: nil)\n\/\/ Voici comment jouer un fichier audio:\nvar player: AVAudioPlayer?\nfunc jouerIntro() {\n   let url = Bundle.main.url(forResource: \"fichier\", withExtension: \"mp3\")!\n   do {\n        player = try AVAudioPlayer(contentsOf: url)\n        guard let player = player else { return } \/\/ autre fa\u00e7on de faire un if let _ {} else {}\n        player.prepareToPlay()\n        player.play()\n       } catch let error {\n            print(error)\n       } \/\/ do\/try\/catch\n} \/\/ func jouerIntro()<\/pre>\n<p><span style=\"color: #ff0000;\"><strong>Action 1.1.3<\/strong><\/span>\u00a0&#8211; Ajoutons le code suivant \u00e0 la m\u00e9thode \u00ab\u00a0<strong><span style=\"color: #ff0000;\">obtenirDonn\u00e9esVersionBloquante<\/span><\/strong>\u00a0\u00bb de la classe contr\u00f4leur de la sc\u00e8ne principale.<\/p>\n<pre class=\"toolbar:1 lang:default decode:true\">\/\/ *** Code \u00e0 ins\u00e9rer dans la m\u00e9thode \"obtenirDonn\u00e9esVersionBloquante\"\n        let strURL = \"http:\/\/prof-tim.cstj.qc.ca\/cours\/xcode\/sources\/timgames\/api.timgames.php?apikey=\\(Globales.CLE_API)&amp;q=\\(chaine)&amp;format=json&amp;quant=\\(tailleRequete.text!)\"\n        let uneURL = URL(string: strURL)!  \/\/Danger!\n        \/\/\/ Ex\u00e9cuter le traitement suivant en parall\u00e8le\n        \/\/\/ DispatchQueue.main.async ( execute: {\n        if let _donn\u00e9es = NSData(contentsOf: uneURL) as? Data {\n            do {\n                let json = try JSONSerialization.jsonObject(with: _donn\u00e9es, options: JSONSerialization.ReadingOptions()) as? Dictionary&lt;String, Any&gt;\n                print(\"Conversion JSON r\u00e9ussie\")\n                self._r\u00e9sultatDeLaRequ\u00eate = json!\n                \/\/ Cr\u00e9er un tableau \u00e0 partir du champ 'resultats'\n                if let listeDesItems = self._r\u00e9sultatDeLaRequ\u00eate[\"resultats\"] as? Array&lt;Dictionary&lt;String, Any&gt;&gt; {\n                    self._listeDesItems = listeDesItems\n                    print(\"Liste des items:\\n\\(self._listeDesItems)\")\n                    self.collectionDesItems.reloadData()\n                }\n                \/\/ print(json)\n            } catch {\n                print(\"\\n\\n#Erreur: Probl\u00e8me de conversion json:\\(error)\\n\\n\")\n            } \/\/ do\/try\/catch\n        } else\n        {\n            print(\"\\n\\n#Erreur: impossible de lire les donn\u00e9es via:\\(strURL)\\n\\n\")\n        } \/\/ if let _donn\u00e9es = NSData\n        \/\/\/ }) \/\/ DispatchQueue.main.async<\/pre>\n<p><span style=\"color: #ff0000;\"><strong>Action\u00a01.2<\/strong><\/span>\u00a0&#8211;\u00a0Testons l&rsquo;application. \u00a0Remarquez que la m\u00e9thode &lsquo;<span style=\"color: #ff0000;\">obtenirDonn\u00e9esVersionBloquante<\/span>&lsquo; est appel\u00e9e dans &lsquo;viewDidLoad&rsquo;.<br \/>\n<a href=\"\/xcode\/wp-content\/uploads\/2016\/10\/TIM.Ze_.Game-cap20.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-medium wp-image-2957\" src=\"\/xcode\/wp-content\/uploads\/2016\/10\/TIM.Ze_.Game-cap20-744x600.png\" alt=\"TIM.Ze.Game-cap20\" width=\"744\" height=\"600\" \/><\/a><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\">{\n    \"info\": {\n        \"api.TIMGames\": \"version 2016.10.01\",\n        \"Auteur_API\": \"Alain Boudreault, AKA Puyansude, AKA ve2cuy\",\n        \"type_requete\": \"json\",\n        \"recherche\": \"je vais \",\n        \"apikey\": \"ceciEstUltraSecret\",\n        \"droit_auteur\": \"Cette API est \\u00e0 l'usage exclusif des \\u00e9tudiantes et \\u00e9tudiants de 'Production Multim\\u00e9dia sur Support' de tim.cstj.qc.ca'\",\n        \"site_web\": \"http:\\\/\\\/prof-tim.cstj.qc.ca\\\/cours\\\/xcode\\\/wp\\\/index.php\\\/contenu\\\/\",\n        \"nombre\": \"2\",\n        \"addresse_IP\": \"192.226.187.50\",\n        \"date\": {\n            \"seconds\": 49,\n            \"minutes\": 43,\n            \"hours\": 14,\n            \"mday\": 18,\n            \"wday\": 2,\n            \"mon\": 10,\n            \"year\": 2016,\n            \"yday\": 291,\n            \"weekday\": \"Tuesday\",\n            \"month\": \"October\",\n            \"0\": 1476816229\n        }\n    },\n    \"resultats\": [\n        {\n            \"titre\": \"Dqprzfuwkkf\",\n            \"editeur\": \"TIMGames\",\n            \"annee\": 2012,\n            \"rang_semaine\": 83,\n            \"pochettes\": {\n                \"petite\": \"21p.jpg\",\n                \"grande\": \"21.jpg\"\n            },\n            \"description\": \"Debwusy rcexuwj \",\n            \"like_facebook\": 1595,\n            \"like_twitter\": 6386,\n            \"cotes\": {\n                \"critiques\": 10,\n                \"joueurs\": 9\n            },\n            \"suiveux\": [\n                {\n                    \"nom\": \"Gthqynsuh\",\n                    \"avatar\": \"avatar-16.jpg\"\n                },\n                {\n                    \"nom\": \"Lsicwo q\",\n                    \"avatar\": \"avatar-27.jpg\"\n                }\n            ]\n        },\n        {\n            \"titre\": \"Kkroahfanaxzlcff\",\n            \"editeur\": \"TIMGames\",\n            \"annee\": 1989,\n            \"rang_semaine\": 80,\n            \"pochettes\": {\n                \"petite\": \"4p.jpg\",\n                \"grande\": \"4.jpg\"\n            },\n            \"description\": \"Debwusy rcexuwj \",\n            \"like_facebook\": 5660,\n            \"like_twitter\": 6975,\n            \"cotes\": {\n                \"critiques\": 2,\n                \"joueurs\": 1\n            },\n            \"suiveux\": [\n                {\n                    \"nom\": \"Kwdzpygar\",\n                    \"avatar\": \"avatar-25.jpg\"\n                },\n                {\n                    \"nom\": \"Qeoeffp\",\n                    \"avatar\": \"avatar-17.jpg\"\n                }\n            ]\n        }\n    ]\n}<\/pre>\n<p><span style=\"color: #008080;\"><strong>NOTE<\/strong><\/span>: En 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>L&rsquo;API renvois un dictionnaire avec deux cl\u00e9s:\u00a0 \u00ab\u00a0<strong>info<\/strong>:Dictionary&lt;String, Any&gt;\u00a0\u00bb et \u00ab\u00a0<strong>resultats<\/strong>:Array&lt;Dictionary&lt;String, Any&gt;&gt;\u00a0\u00bb<\/li>\n<li>Nous obtenons la liste des items par; \u00a0<strong><span style=\"color: #008080;\">items =\u00a0donn\u00e9es[\u00ab\u00a0resultats] as? Array&lt;Dictionary&lt;String, Any&gt;&gt;<\/span><\/strong><\/li>\n<li>Le titre du premier item s&rsquo;obtient par; \u00a0<span style=\"color: #008080;\"><strong>if let titre = items[0][\u00ab\u00a0titre\u00a0\u00bb] as? String {}<\/strong><\/span><\/li>\n<\/ol>\n<p><span style=\"color: #ff0000;\"><strong>Action\u00a01.3<\/strong><\/span>\u00a0&#8211;\u00a0Affichons le titre des items\u00a0re\u00e7us (\u00e0 la fin de la m\u00e9thode: &lsquo;obtenirDonn\u00e9esVersionBloquante&rsquo;)<\/p>\n<pre class=\"toolbar:1 lang:default decode:true\">       \/\/ Afficher le titre des items\n       for (indice,item) in _listeDesItems.enumerated() {\n            if let _titreItem = item[\"titre\"] as? String {\n                print(\"Titre item \\(indice): \\(_titreItem)\")\n            }\n        }\n<\/pre>\n<hr \/>\n<h1><span style=\"color: #ff0000;\">Laboratoire<\/span><\/h1>\n<p>Afficher le nom des suiveux sous le titre des items<\/p>\n<pre class=\"lang:swift decode:true\">-----------------------------------\nTitre: the Rwdqxmoqfuw\n-----------------------------------\nTitre: the Wgy lfypzvqiiieixtw\n\t\tsuiveux: Hlslb\n-----------------------------------\nTitre: the Qzrgfldbscceibuhxk\n\t\tsuiveux: Rguwqsqm b\n\t\tsuiveux: Emdvmv\n<\/pre>\n<p>&nbsp;<\/p>\n<hr \/>\n<h2>\u00c9tape 2 &#8211; Actualiser la requ\u00eate suite \u00e0 &lsquo;textFieldShouldReturn&rsquo;<\/h2>\n<p>Remarquer 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;<span style=\"color: #008080;\"><strong>textFieldShouldReturn<\/strong><\/span>&lsquo; du &lsquo;UITextField&rsquo;\u00a0\u00a0pour relancer la requ\u00eate vers l&rsquo;api TIM.Ze.Game.<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<span style=\"color: #ff0000;\"><strong>Action 2.1<\/strong><\/span>\u00a0&#8211; Effa\u00e7ons les commentaires du\u00a0code de la m\u00e9thode &lsquo;<span style=\"color: #008080;\"><strong>textFieldShouldReturn<\/strong><\/span>&lsquo;\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        \/\/ print(\"textFieldShouldReturn\")\n        \/* *********************************\n         \u00c0 compl\u00e9ter ....\n         ********************************* *\/\n        \/\/ TODO: Convertir la chaine en format 'escaped' pour le web. Par exemple, ' '= %20\n        let escapedText = textField.text!.addingPercentEncoding(withAllowedCharacters: CharacterSet.alphanumerics)!\n        print(\"escapedText = \\(escapedText)\")\n        \/\/ TODO: Relancer la requete vers l'API\n        _ = obtenirDonn\u00e9esVersionBloquante(escapedText)\n        \/\/----------------------------------\n        textField.resignFirstResponder()\n        progression.stopAnimating()\n        return true\n    } \/\/ textFieldShouldReturn<\/pre>\n<p><span style=\"color: #ff0000;\"><strong>Action\u00a02.2<\/strong><\/span>\u00a0&#8211;\u00a0Testons l&rsquo;application<br \/>\n<strong><span style=\"color: #008080;\">R\u00e9sultat: <\/span><\/strong>La chaine de saisie de recherche a \u00e9t\u00e9 encod\u00e9 en caract\u00e8res\u00a0d&rsquo;\u00e9chappement WEB.<\/p>\n<hr \/>\n<h2>\u00c9tape 3 &#8211; Renseigner les \u00a0cellules du UICollectionView<\/h2>\n<p>Nous 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><span style=\"color: #008080;\"><strong>UIImage(Named:\u00a0\u00bbpochette.jpg\u00a0\u00bb)<\/strong><\/span><\/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><span style=\"color: #ff0000;\">do<\/span> {<br \/>\nlet _data = <span style=\"color: #ff0000;\">try<\/span> <strong><span style=\"color: #008080;\">Data(contentsOf: _url, options: Data.ReadingOptions.alwaysMapped)<\/span><\/strong><br \/>\ncellule.pochetteImage.image = <span style=\"color: #008080;\"><strong>UIImage(data: _data)<\/strong><\/span><br \/>\n}<br \/>\n<span style=\"color: #ff0000;\">catch<\/span> \u00a0{\u00a0}<\/p><\/blockquote>\n<p><span style=\"color: #ff0000;\"><strong>Note<\/strong><\/span>: 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<span style=\"color: #ff0000;\"><strong>Action 3.1<\/strong><\/span>\u00a0&#8211; \u00a0Rempla\u00e7ons\u00a0la m\u00e9thode &lsquo;<strong>cellForItem<\/strong>&#8230;&rsquo; du fichier <strong>ViewController.swift<\/strong>\u00a0\u00bb par:<\/p>\n<pre class=\"toolbar:1 lang:default mark:12 decode:true\">    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -&gt; UICollectionViewCell {\n        let cellule = collectionView.dequeueReusableCell(withReuseIdentifier: \"modeleCellule1\", for: indexPath) as! CollectionViewCellPerso1\n        \/\/ TODO: 5a - Renseigner les \u00e9l\u00e9ments d'interface de la cellule courante: titre, image, ...\n        let itemCourant = _listeDesItems[indexPath.row]\n        let nomFichierPetitePochette = (itemCourant[\"pochettes\"] as? Dictionary&lt;String, String&gt;)?[\"petite\"]\n        let URLFichierImage = \"\\(Globales.URLDonn\u00e9es)\\(nomFichierPetitePochette!)\"\n        print(URLFichierImage)\n        cellule.pochetteTitre.text = itemCourant[\"titre\"] as? String\n        \/\/ Version tr\u00e8s bloquante:\n        if let _url = URL(string: URLFichierImage) {\n            do {\n                let _data = try Data(contentsOf: _url, options: Data.ReadingOptions.alwaysMapped)\n                cellule.pochetteImage.image = UIImage(data: _data)\n            }\n            catch  {\n                print(\"Ligne \\(#line), \\(error), ### Exception: Probl\u00e8me avec URL: \\(URLFichierImage)\")\n                cellule.pochetteImage.image = UIImage(named:Globales.NA_IMAGE)\n            }\n        } \/\/ if let _url\n        \/\/ TODO: 5b - Renseigner les \u00e9l\u00e9ments d'interface en version non bloquante\n        \/\/ Renseigner la couleur de l'ent\u00eate indexPath.row modulo 2\n        let couleur1 = UIColor.init(red: 140 \/ 255.0, green: 188 \/ 255.0, blue: 220 \/ 255.0, alpha: 1)\n        let couleur2 = UIColor.init(red: 108 \/ 255.0, green: 145 \/ 255.0, blue: 168 \/ 255.0, alpha: 1)\n        let couleur = indexPath.row % 2 == 0 ? couleur1 : couleur2\n        cellule.entete.backgroundColor = couleur\n        return cellule\n    } \/\/ collectionView: cellForItemAt<\/pre>\n<p><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  return _listeDesItems.count\n} \/\/ numberOfItemsInSection<\/pre>\n<p><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\">    \/\/ MARK: Pr\u00e9parer les donn\u00e9es pour le segue vers la sc\u00e8ne D\u00e9tails:\n    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {\n        let destination = segue.destination as! ViewControllerDetails\n        destination.detailsItemCourant = _listeDesItems[(collectionDesItems.indexPath(for: sender as! UICollectionViewCell)?.row)!]\n    }<\/pre>\n<p><span style=\"color: #ff0000;\"><strong>Action\u00a03.4<\/strong><\/span>\u00a0&#8211;\u00a0Testez l&rsquo;application. \u00a0<span style=\"color: #ff0000;\">Vous allez remarquer un important manque de r\u00e9ponse de l&rsquo;application.<\/span><\/p>\n<hr \/>\n<h1><span style=\"color: #ff0000;\">Laboratoire<\/span><\/h1>\n<p>Dans la sc\u00e8ne \u00ab\u00a0D\u00e9tails\u00a0\u00bb, renseignez la grande image de la pochette et la liste des suiveux (nom et image).<br \/>\n&nbsp;<\/p>\n<hr \/>\n<h2>\u00c9tape 4 &#8211; Am\u00e9liorer l&rsquo;exp\u00e9rience utilisateur<\/h2>\n<p>Pr\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 \/>\n&nbsp;<br \/>\n<span style=\"color: #ff0000;\"><strong>Action 4.1<\/strong><\/span>\u00a0&#8211;\u00a0Modifions la m\u00e9thode &lsquo;obtenirDonn\u00e9esVersionBloquante&rsquo; pour rendre la requ\u00eate non bloquante<\/p>\n<pre class=\"lang:default decode:true\">       \/\/\/ Ex\u00e9cuter le traitement suivant en parall\u00e8le\n       \/\/ Supprimer le commentaire des lignes suivantes:\n       DispatchQueue.main.async ( execute: {\n         ...\n       }) \/\/ DispatchQueue.main.async\n<\/pre>\n<p><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 une technique <strong><span style=\"color: #008080;\">similaire<\/span><\/strong> pour charger les images via le r\u00e9seau Internet.<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 les lignes de code \u00a0qui charge l&rsquo;image via une URL par ceci:<\/p>\n<pre class=\"toolbar:1 lang:default mark:6 decode:true\">       cellule.pochetteImage.image = UIImage(named:Globales.LOADING_IMAGE)\n       ImageViaURL.obtenirImage(urlStr: URLFichierImage, uneimage: cellule.pochetteImage)\n<\/pre>\n<p><span style=\"color: #ff0000;\"><strong>Action\u00a04.3.1<\/strong><\/span>\u00a0&#8211;\u00a0Analysons la m\u00e9thode :\u00a0<span style=\"color: #ff0000;\">ImageViaURL.obtenirImage()<\/span><\/p>\n<pre class=\"lang:swift decode:true \">    \/\/\/ **********************************************\n    static func obtenirImage(urlStr:String, uneimage: UIImageView){\n        \/\/ Pr\u00e9parer et lancer la requ\u00eate\n        let request = URLRequest(url: NSURL(string:urlStr ) as! URL)\n        let session = URLSession.shared\n        let task = session.dataTask(with: request,\n                                    completionHandler: {data, response, error -&gt; Void in\n                                        if (error == nil) {\n                                            DispatchQueue.main.async ( execute:\n                                                {\n                                                    if let _data = data {\n                                                        uneimage.image = UIImage(data: _data)\n                                                    } else\n                                                    {\n                                                        uneimage.image = UIImage(named: Globales.NA_IMAGE)\n                                                    }\n                                                }\n                                            )  \/\/ DispatchQueue.main.async()\n                                        } else { \/\/ erreur d'URL\n                                            uneimage.image = UIImage(named: Globales.NA_IMAGE)\n                                        }\n        })\n        task.resume()  \/\/ Reprendre le traitement de la session pour qu'elle puisse se terminer.\n    } \/\/ obtenirImage<\/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\u00e9tails&rsquo; pour que le chargement des images\u00a0ne soit plus bloquant.<br \/>\n&nbsp;<\/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:<br \/>\n<a href=\"https:\/\/github.com\/SwiftyJSON\/SwiftyJSON\">https:\/\/github.com\/SwiftyJSON\/SwiftyJSON<\/a><br \/>\nLa fa\u00e7on la plus simple de 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 \/>\nVoici un exemple d&rsquo;utilisation:<br \/>\n<span style=\"color: #ff0000;\"><strong>Action<\/strong><\/span>: Ajoutons le code suivant au projet:<\/p>\n<pre class=\"lang:swift mark:8-9 decode:true\">    func testerJSON(){\n        let strURL = \"http:\/\/prof-tim.cstj.qc.ca\/cours\/xcode\/sources\/timgames\/api.timgames.php?apikey=\\(Globales.CLE_API)&amp;q=&amp;format=json&amp;quant=50\"\n        \/\/\/ Ex\u00e9cuter le traitement suivant en parall\u00e8le\n            if let _donn\u00e9es = NSData(contentsOf: URL(string: strURL)!) as? Data {\n                let json = JSON(data: _donn\u00e9es)\n                if let titre = json[\"resultats\"][0][\"titre\"].string {\n                    print(\"Le titre du premier Item est \\(titre)\")\n                }\n                let imagePochette = json[\"resultats\"][0][\"pochettes\"][\"grande\"].string\n                print(imagePochette)\n               for item in json[\"resultats\"].arrayValue {\n                        print(\"-------------------------\")\n                        print(\"Titre \" + item[\"titre\"].string!)\n               }\n        }\n    }<\/pre>\n<p><span style=\"color: #ff0000;\"><strong>Action<\/strong><\/span>: Testons le code<br \/>\n&nbsp;<\/p>\n<hr \/>\n<h1><span style=\"color: #ff0000;\"><strong>Laboratoire<\/strong><\/span><\/h1>\n<p>En utilisant la\u00a0classe JSON, il faut afficher le titre et le nom des\u00a0suiveux de tous les items.<br \/>\nPar exemple,<\/p>\n<pre class=\"lang:swift decode:true\">-----------------------------------\nTitre: the Zzigzbzxqwk\n\t\tsuiveux: Jhasvei jp\n\t\tsuiveux: Lzkrule\n-----------------------------------\nTitre:  the Baoa xhz hx\n\t\tsuiveux: Qdhamithnb\n\t\tsuiveux: Iysuycm\n\t\tsuiveux: Spruqgwq\n\t\tsuiveux: Deqdmnv\n\t\tsuiveux: Qvwcd\n\t\tsuiveux: Plssu\n-----------------------------------\nTitre: the Nzjlqerpmzylbd\n-----------------------------------\n<\/pre>\n<hr \/>\n<h3><span style=\"color: #ff0000;\">Solution:<\/span><\/h3>\n<pre class=\"lang:swift decode:true \">import Alamofire\nimport RxSwift\nimport RxCocoa\nimport SwiftyJSON\n\/\/\/\nvar resultat:JSON?\n\/\/\/\nlet strURL = \"http:\/\/prof-tim.cstj.qc.ca\/cours\/xcode\/sources\/timgames\/api.timgames.php?apikey=ceciEstUltraSecret&amp;q=&amp;format=json&amp;quant=5\"\nAlamofire.request(strURL).response { response in \/\/ method defaults to `.get`\n    debugPrint(response)\n    self.resultat = JSON(data: response.data!)\n    \/\/ print(self.resultat as Any)\n    for item in (self.resultat?[\"resultats\"].arrayValue)! {\n        print(\"-------------------------\")\n        print(\"Titre \" + item[\"titre\"].string!)\n        for suiveux in item[\"suiveux\"].arrayValue {\n            print(\"\\tsuiveux: \\(suiveux[\"nom\"].stringValue)\")\n        } \/\/ for suiveux\n    } \/\/ for item\n} \/\/ Alamofire.request(strURL).response<\/pre>\n<hr \/>\n<p>&nbsp;<\/p>\n<h1>Autres APIs<\/h1>\n<p>Voici une liste d&rsquo;APIs disponibles via le web:<\/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><\/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>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><\/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>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>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><\/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><\/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 style=\"text-align: right;\"><strong><span style=\"color: #003366;\">Document par Alain Boudreault (c) 2016<\/span><\/strong><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Utilisation d&rsquo;une &lsquo;API&rsquo; web R\u00e9vision du 2017.01.04 &#8211; conversion vers Xcode\u00a08.0 et utilisation de Alamofire\u00a0 Dans le tutoriel\u00a0TIMFlix\u00a0ou &lsquo;Les Amis de la science\u00ab\u00a0, 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 [&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-2938","page","type-page","status-publish","hentry"],"_links":{"self":[{"href":"https:\/\/ve2cuy.com\/xcode\/wp-json\/wp\/v2\/pages\/2938","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=2938"}],"version-history":[{"count":0,"href":"https:\/\/ve2cuy.com\/xcode\/wp-json\/wp\/v2\/pages\/2938\/revisions"}],"wp:attachment":[{"href":"https:\/\/ve2cuy.com\/xcode\/wp-json\/wp\/v2\/media?parent=2938"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}