Utilisation d'une 'API' web.json.Codable


 Les éléments de compétences de ce laboratoire

Chameleon-1
Pré-requis:
Avoir complété le tutoriel TIMFlix ou bien le laboratoire ‘Les amis de la science‘, ou bien avoir une maitrise de l’objet UITableView + segue + passage de paramètres entre les scènes d’une app.
 


Praeambulum

Dans le tutoriel TIMFlix ou celui ‘Des Amis de la science‘, nous avons construit une application qui affichait une liste de données à l’intérieur d’un UITableView.

L’inconvénient de cette approche est évident lorsque vient le temps d’y ajouter de nouvelles données.
Dans ce tutoriel, nous verrons comment utiliser une API Web comme source de données à une application Xcode.
Historiquement, il a toujours été un peu complexe et lourd de traiter des données en format JSON sous swift.  Nous pouvions nous rabattre sur des classes comme swiftyJSON pour alléger la tâche.
À partir de la version 4,  swift propose les protocoles ‘Decodable‘ et ‘Encodable‘ pour le traitement facile des conversions de JSON vers des structures de données natives au langage et vice versa.  L’alias ‘Codable’ représente ses deux protocoles
Note: Le protocole ‘Codable‘ n’est disponible qu’à partir de la version 4 de Xcode.  Ce laboratoire est aussi disponible, sans le protocole ‘Codable’, pour la version 3 de swift.

Révision du 2017.10.25 – conversion vers Xcode 9.0, swift 4 et utilisation du protocole ‘Codable’. 


1 – Une API web d’accès à des données

Explications

C’est une  pratique courante que d’offrir l’accès à des données d’un SGBD (système de gestion de la base de données)  via des URLs web selon la méthode RESTful.
L’avantage de cette approche est qu’il n’est pas nécessaire d’offrir un accès direct au SGBD de l’organisation.
Exemples d’accès direct au SGBD;

Une solution à cet accès direct est d’offrir des scripts de type ‘serveur web’ de traitements et d’accès à la base de données.
Ces scripts, écrits en PHPASPPython ou en node,js,  peuvent alors être lancés à partir d’une simple requête HTTP, soit dans un fureteur ou à partir d’une application, en utilisant des fonctions ou des objets tel que curl()NSArray(URL:) et autres.
Voir la définition de Representational State Transfer.


2 – Le format des données

Suite au traitement des données, le script serveur pourra retourner les données dans un format indépendant du SGBD tel que;

Par exemple, l’URL suivante,
https://uneApi.org/obtenir_liste_stages.php?region=mtl&format=csv,
retourne la liste des lieux de stages de la région de Montréal en format csv:

‘Ubisoft’,2,’Hiv18′
‘Gameloft’,0,’Hiv18′
‘TIM.cie’,7,’Été59′


3 – Comment programmer une API Web

Pour programmer une API Web d’accès à une base de données il suffit d’avoir accès à un serveur Web (IIS, Apache, …), à un langage script coté serveur (php, ASP, node.JS, …) et à un SGBD (MySQL, MSSQL, Oracle, PostgreSQL, … ).
Dans le cadre d’apprentissages, une solution comme WAMP ou LAMP est idéale.

Exemple pratique

Voici comment programmer une API Web, d’interrogation d’une table SQL, retournant une liste de pensées du jour: 
API.TIM.01 – À partir d’une table, ‘penseesdujours‘:
apitim_01
API.TIM.02 – Et du script PHP suivant

// Requête SQL pour obtenir les enregistrements de la table penseesdujours
// Connexion à la BD
mysql_connect("localhost", "user", "password")  or die(mysql_error());
mysql_select_db("cours_xcode") or die(mysql_error());
// Exécuter un requête SQL
$res = mysql_query("SELECT `nom_ajout` ,  `created_at` ,  `adresse_ip` , `pensee_texte`,  `pensee_auteur`,  `pensee_lien_image` FROM penseesdujours") or die(mysql_error());
// Parcourir les éléments du tableau de résultats
while($r = mysql_fetch_assoc($res)) {
  $xx = array_map("utf8_encode", $r);
  foreach ($xx as $key => $value) {
    echo "clef = $key, valeur = $value\n";
  } // foreach
} // while encore un résultat

API.TIM.03 – L’API retournera le résultat texte suivant:

clef = nom_ajout, valeur = Alain
clef = created_at, valeur = 2014-11-01 05:11:43
clef = categorie, valeur = 3
clef = adresse_ip, valeur = 24.200.185.163
clef = pensee_texte, valeur = Il etait une fois un gars …
clef = pensee_auteur, valeur = Moi
clef = 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

 lien de test
API.TIM.04 – Voici un script PHP qui retourne le résultat en format ‘Apple plist‘:

echo '<?xml version="1.0" encoding="UTF-8"?>'."\n";
echo '<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">'."\n";
echo '<plist version="1.0">'."\n";
echo "<!-- Liste générée par l'API TIM le ".date('Y-m-d h:m:s')." -->\n";
echo "<!-- (c) 2014-2016 par Alain Boudreault -->\n";
echo "<array>\n";
while($r = mysql_fetch_assoc($res)) {
  $xx = array_map("utf8_encode", $r);
  echo "\t<dict>\n";
  foreach ($xx as $key => $value) {
    echo "\t\t<key>".$key."</key>\n\t\t<string>".$value."</string>\n";
  } // foreach
  echo "\t</dict>\n";
} // while
echo "</array>\n</plist>";

Note: Plusieurs classes du framework ‘Foundation‘ de Xcode savent travailler directement avec ce type de fichier. Voir la structure d’un fichier ‘plist’ sous Xcode:
API.TIM.05 – Produira le résultat suivant:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<!-- Liste générée par l'API TIM le 2017-10-25 09:11:55 -->
<!-- (c) 2014-2017 par Alain Boudreault -->
<array>
	<dict>
		<key>nom_ajout</key>
		<string>Alain</string>
		<key>created_at</key>
		<string>2014-11-01 06:11:47</string>
		<key>adresse_ip</key>
		<string>24.200.185.163</string>
		<key>pensee_texte</key>
		<string>On ne reçoit pas la sagesse, il faut la découvrir soi-même, après un trajet que personne ne peut faire pour nous, ne peut nous épargner.</string>
		<key>pensee_auteur</key>
		<string>Marcel Proust</string>
		<key>pensee_lien_image</key>
		<string>http://upload.wikimedia.org/wikipedia/commons/thumb/7/7e/Marcel_Proust_1900.jpg/220px-Marcel_Proust_1900.jpg</string>
	</dict>
</array>
</plist>

lien de test 
API.TIM.06 – Un script PHP de mise en format ‘JSON

// tableau du résultat final
$resultat = array();
$resultat['info'] = array("API_TIM" => "version 2017.10.26", "type_requete" => Input::get('mode'));
while($r = mysql_fetch_assoc($res)) {
  // Encoder les caractères accentués.
  $tableauAvecAccents[] = array_map("utf8_encode", $r);
} // while
$resultat['resultat'] = $tableauAvecAccents;
// Convertir un tableau en format JSON
echo json_encode($resultat);

API.TIM.07 – Produira le résultat suivant:

{
  "info":{"API_TIM":"version 2017.10.25","type_requete":"rnd"},
  "resultat":[
                { "nom_ajout":"admin",
                  "created_at":"2014-11-01 10:11:56",
                  "adresse_ip":"24.200.185.163",
                  "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",
                  "pensee_auteur":"Jacques Brel",
                  "pensee_lien_image":"https:\/\/encrypted-tbn2.gstatic.com\/images?q=tbn:ANd9GcQqWOL6fBMrhIECWoOuY3aEdxrm6biaZTdi5Kp72TC_xG9L11GS"
                },
                ...
             ]
}

lien de test
Exemple php complet:

<?php
// -------------------------------------------------------------------
// Fichier:      apitim.php
// Par:          Alain Boudreault
// Date:         2016.10.23
// -------------------------------------------------------------------
// Description:  Exemple d'un script qui retourne, vers le client Web,
//               le contenu d'un table SQL dans un
//               des trois formats suivants:
//
//               texte, plist ou json.
//
// Note:         Cette application a été développée pour les étudiants
//               et étudiantes du cours
//
//               ProductionMultimédiaSurSupport.tim.cstj.qc.ca
// -------------------------------------------------------------------
// M-A-J: A.B. 2017.10.25 - Ajout de commentaires
//        A.B. 2017.10.25 - Correction des dates
// -------------------------------------------------------------------
$servername = "localhost";
$username   = "votreAcces";
$password   = "votreMotDePasse";
$dbname     = "votreBD";
$mode   = isset($_GET["mode"]) ? $_GET["mode"] : "all";
$quant  = isset($_GET["quant"]) ? $_GET["quant"] : "2";
$format = isset($_GET["format"]) ? $_GET["format"] : "texte";
// Create connection
$conn = new mysqli($servername, $username, $password, $dbname);
// Check connection
if ($conn->connect_error) {
    die("Connection failed: " . $conn->connect_error);
}
$sql = "SELECT `nom_ajout` ,  `created_at`, `categorie`, `adresse_ip` , `pensee_texte`,  `pensee_auteur`,  `pensee_lien_image`  FROM penseesdujours";
if ($mode == "all") {
    $sql = "SELECT `nom_ajout` ,  `created_at`, `categorie`, `adresse_ip` , `pensee_texte`,  `pensee_auteur`,  `pensee_lien_image` FROM penseesdujours";
}  // mode=all
if ($mode == "rnd") {
    $sql = "SELECT `nom_ajout` ,  `created_at`,`categorie`, `adresse_ip` , `pensee_texte`,  `pensee_auteur`,  `pensee_lien_image` FROM penseesdujours ORDER BY RAND() LIMIT $quant";
} // mode=rnd
if ($mode == "adulte") {
    $sql = "SELECT * FROM (SELECT `categorie`,`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";
    echo $sql . "\n\n";
} // mode=adulte
$res = $conn->query($sql);
// En format plist
if ($format == "plist") {
  echo '<?xml version="1.0" encoding="UTF-8"?>'."\n";
  echo '<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">'."\n";
  echo '<plist version="1.0">'."\n";
  echo "<!-- Liste générée par l'API TIM le ".date('Y-m-d h:m:s')." -->\n";
  echo "<!-- (c) 2014-2017 par Alain Boudreault -->\n";
  echo "<array>\n";
  while($r = $res->fetch_assoc()) {
    $xx = array_map("utf8_encode", $r);
    echo "\t<dict>\n";
    foreach ($xx as $key => $value) {
      echo "\t\t<key>".$key."</key>\n\t\t<string>".$value."</string>\n";
    } // foreach
    echo "\t</dict>\n";
  } // while
  echo "</array>\n</plist>";
} // format = plist
// En format texte
if ($format == "texte") {
  // Liste simple
  while($row = $res->fetch_assoc()) {
    foreach ($row as $key => $value) {
       echo "clef = ".$key.", valeur = ".$value."<br>\n";
     } // foreach
  } // while
} // if format == texte
// En format json
if ($format == "json") {
  // tableau du résultat final
  $resultat = array();
  $resultat['info'] = array("API_TIM" => "version 2017.10.25", "type_requete" => "json");
  while($r = $res->fetch_assoc()) {
    // Encoder les caractères accentués.
    $tableauAvecAccents[] = array_map("utf8_encode", $r);
  } // while
  $resultat['resultat'] = $tableauAvecAccents;
  // Convertir un tableau en format JSON
  echo json_encode($resultat, JSON_PRETTY_PRINT);
} // if format == json
$conn->close();
//   echo phpinfo();
?>

4 – Obtenir des données json via une URL

Nous allons maintenant analyser un projet qui utilise l’API.TIM des pensées du jour.
Le but du projet est;

Action 4.1 – Cloner le projet suivant :

$ git clone https://github.com/ve2cuy/conversion-de-donnees-json-par-le-protocole-codable.git

 
Action 4.2 – Analyser, en suivant les directives de l’enseignant,  les fichiers de la branche ‘master’

extension ViewController {
    //MARK:- Obtenir les données
    // =======================================================
    func obtenirLaCitationDuJour(){
       let uneURL = "http://prof-tim.cstj.qc.ca/cours/xcode/sources/apitim.php?mode=rnd&quant=5&format=json"
        if let _data = NSData(contentsOf: URL(string: uneURL)!) as Data? {
            // Note: Class.self veut dire "de type Class"
            let données = try! JSONDecoder().decode(Citation.self, from: _data)
            print(données)
            for contenu in données.resultat {
                // Note: ?? est le 'nil-coalescing operator'
                let auteur = contenu.pensee_auteur ?? "Erreur: Nom de l'auteur non disponible"
                let pensée = contenu.pensee_texte  ?? "Erreur: Pensée de l'auteur non disponible"
                print ("\(auteur) a dit:\n\t \(pensée)\n\n")
            }
        } // if let
    } // obtenirLaCitationDuJour()
}
//  Citation.swift
//  --------------------------------------------
//  Created by Alain on 17-10-25.
//  Copyright © 2017 Alain. All rights reserved.
//
import Foundation
class Citation: Codable {
    var info: Dictionary<String, String>
    var resultat: Array<DetailCitation>
} // Citation
struct DetailCitation:Codable {
    var categorie: String
    var pensee_auteur: String?
    var pensee_texte: String?
} // DetailCitation

Action 4.3 – Tester l’application
Action 4.4 – À réaliser par l’étudiant,
a) Remplacer la déclaration suivante:

    var info: Dictionary<String, String>

par la structure ‘Information
Note: Il faut créer cette structure en observant les informations retournées par l’API.
b) Ajouter, à la structure ‘DetailCitation’, une propriété – de type optionnel – pour le lien de l’image .


5 – L’utilisation de l’API ‘finance’ de Yahoo

Yahoo offre des nombreuses APIs permettant d’exploiter des données de plusieurs domaines.
Comme par exemple, la météo, le taux de change des devises, la valeur des actions, …
Voici un exemple d’interrogation du service des finances de Yahoo:
Obtenir cotes de la bourse via l’API finance de Yahoo
« &env=store://datatables.org/alltableswithkeys&format=json »
Retourne la structure suivante:

{
    "query":{  // Dictionary<String, Any>
             "count":4,
             "created":"2016-11-01T15:53:16Z",
             "lang":"fr-ca",
             "results": {  // Dictionary<String, Any>
                  // *** Tableau des cotes
		  "quote":[ // Array<Dictionary<String, Any>>
		    // ****  Premier élément
	          {     "symbol":"YHOO",
   	                "Ask":"40.89",
     		        "AverageDailyVolume":"10498500",
        	        "Bid":"40.86",
          	        "AskRealtime":null,
                    "BidRealtime":null,
                    "BookValue":"36.39",
                    "Change_PercentChange":"-0.23 - -0.55%",
                    "Change":"-0.23",
                    "Commission":null,
                    "Currency":"USD",
                    "ChangeRealtime":null,
                    "AfterHoursChangeRealtime":null,
                    "DividendShare":null,
                    "LastTradeDate":"10/31/2016",
                    "TradeDate":null,
                    "EarningsShare":"-5.11",
                    "ErrorIndicationreturnedforsymbolchangedinvalid":null,
                    "EPSEstimateCurrentYear":"0.58",
                    "EPSEstimateNextYear":"0.62",
                    "EPSEstimateNextQuarter":"0.14",
                    "DaysLow":null,
                    "DaysHigh":null,
                    "YearLow":"26.15",
                    "YearHigh":"44.92",
                    "HoldingsGainPercent":null,
                    "AnnualizedGain":null,
                    "HoldingsGain":null,
                    "HoldingsGainPercentRealtime":null,
                    "HoldingsGainRealtime":null,
                    "MoreInfo":null,
                    "OrderBookRealtime":null,
                    "MarketCapitalization":"39.78B",
                    "MarketCapRealtime":null,
                    "EBITDA":"90.38M",
                    "ChangeFromYearLow":"15.40",
                    "PercentChangeFromYearLow":"+58.89%",
                    "LastTradeRealtimeWithTime":null,
                    "ChangePercentRealtime":null,
                    "ChangeFromYearHigh":"-3.37",
                    "PercebtChangeFromYearHigh":"-7.50%",
                    "LastTradeWithTime":"4:00pm - <b>41.55</b>",
                    "LastTradePriceOnly":"41.55",
                    "HighLimit":null,
                    "LowLimit":null,
                    "DaysRange":null,
                    "DaysRangeRealtime":null,
                    "FiftydayMovingAverage":"42.83",
                    "TwoHundreddayMovingAverage":"39.65",
                    "ChangeFromTwoHundreddayMovingAverage":"1.90",
                    "PercentChangeFromTwoHundreddayMovingAverage":"+4.78%",
                    "ChangeFromFiftydayMovingAverage":"-1.28",
                    "PercentChangeFromFiftydayMovingAverage":"-2.98%",
                    "Name":"Yahoo! Inc.",
                    "Notes":null,
                    "Open":null,
                    "PreviousClose":"41.78",
                    "PricePaid":null,
                    "ChangeinPercent":"-0.55%",
                    "PriceSales":"8.04",
                    "PriceBook":"1.15",
                    "ExDividendDate":null,
                    "PERatio":null,
                    "DividendPayDate":null,
                    "PERatioRealtime":null,
                    "PEGRatio":"-124.19",
                    "PriceEPSEstimateCurrentYear":"71.64",
                    "PriceEPSEstimateNextYear":"67.02",
                    "Symbol":"YHOO",
                    "SharesOwned":null,
                    "ShortRatio":"4.25",
                    "LastTradeTime":"4:00pm",
                    "TickerTrend":null,
                    "OneyrTargetPrice":"45.14",
                    "Volume":"10108",
                    "HoldingsValue":null,
                    "HoldingsValueRealtime":null,
                    "YearRange":"26.15 - 44.92",
                    "DaysValueChange":null,
                    "DaysValueChangeRealtime":null,
                    "StockExchange":"NMS",
                    "DividendYield":null,
                    "PercentChange":"-0.55%"},
                    // *** Deuxième élément
                    {"symbol":"AAPL","Ask":"113.60", ... }
		] // **** Fin du tableau des cotes
	   }  // results
     } // query
}

 
Voici comment obtenir et traiter ces données:

    // =======================================================
    func obtenirDonnéesDeMesActions(){
        // Exemple d'utilisation de l'API finance Yahoo:
        // http://query.yahooapis.com/v1/public/yql?q=select * from yahoo.finance.quotes where symbol in ('MSFT','YHOO','FB','INTC','HPQ','AAPL','AMD','COKE')&env=store://datatables.org/alltableswithkeys&format=json
        // Il faudra convertir certains caractères en séquence d'échappement WEB
        // pour rendre l'URL compatible avec la classe URL.
        // http://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20yahoo.finance.quotes%20where%20symbol%20in%20('MSFT','YHOO','FB','INTC','HPQ','AAPL','AMD','COKE')&env=store://datatables.org/alltableswithkeys&format=json
        // Construire l'URL vers l'API finance de Yahoo et remplacer les caractères invalides.
        // Liste des car à convertir
        let caracteresAConvertirEnFormatWeb = CharacterSet(charactersIn: " ").inverted
        // Former le début de l'URL
        let uneURL = "http://query.yahooapis.com/v1/public/yql?q="
            // Ajouter la requête SQL et remplacer les ' ' par %20
            + "select * from yahoo.finance.quotes where symbol in ('MSFT','YHOO','FB','INTC','HPQ','AAPL','AMD','COKE')".addingPercentEncoding(withAllowedCharacters: caracteresAConvertirEnFormatWeb)!
            // Ajouter la fin de l'URL
            + "&env=store://datatables.org/alltableswithkeys&format=json"
        //MARK:- Exécuter la commande seulement en mode DEBUG
        #if DEBUG
         print(uneURL)
        #endif
        if let _data = NSData(contentsOf: URL(string: uneURL)!) as Data? {
            // Note: YahooFinance veut dire "de type YahooFinance"
            let données = try! JSONDecoder().decode(YahooFinance.self, from: _data)
            print(données)
            for contenu in données.query.results.quote {
                let prix = contenu.Ask ?? "Prix non disponible"
                print ("\(contenu.Symbol): \(prix)")
            }
        } // if let
    } // obtenirDonnéesDeMesActions

 
Action 5.1 – Enlever le commentaire devant la ligne: ‘// obtenirDonnéesDeMesActions()’ et Tester l’application.
Résultat obtenu:

MSFT: 79.07
YHOO: Prix non disponible
FB: 171.10
INTC: 40.90
HPQ: 21.640
AAPL: 157.53
AMD: 12.0800
COKE: 225.5000

L’affichage est réalisé par le code suivant:

// Afficher le symbole ainsi que le prix des actions.
for contenu in données.query.results.quote {
    let prix = contenu.Ask ?? "Prix non disponible"
    print ("\(contenu.Symbol): \(prix)")
}

6 – Exécution d’une requête en parallèle avec l’application:

Action 6.1 – Faire un ‘checkout‘ sur la branche ‘CGDDepart’ du projet précédent.
Action 6.2 – Analyser le code suivant:

    override func viewDidLoad() {
        super.viewDidLoad()
        obtenirDonnéesDeMesActions()
        afficherDonnéesFinanceYahoo()
    } // viewDidLoad()

 
Action 6.3 – Tester l’application.

============================================
Voici les données du portefeuille d'actions:
Début ------------------------------------->
	MSFT: 84.00
	YHOO: Prix non disponible
	FB: 177.87
	INTC: 44.60
	HPQ: Prix non disponible
	AAPL: 162.94
	AMD: 11.84
	COKE: Prix non disponible
Fin <---------------------------------------

 
Action 6.4 – Retirer le commentaire des lignes suivantes (2 et 8):

        // TODO: Retirer le commentaire suivant
        // DispatchQueue.main.async ( execute: {
            // Obtenir les données via le Web
            if let _data = NSData(contentsOf: URL(string: uneURL)!) as Data? {
                // Note: YahooFinance.self veut dire "de type YahooFinance"
                self.donnéesFinanceYahoo = try! JSONDecoder().decode(YahooFinance.self, from: _data)
            } // if let
        // TODO: Retirer le commentaire suivant
        // }) // DispatchQueue()

 
Action 6.5 – Tester l’application.
Analysons le résultat obtenu:

============================================
Voici les données du portefeuille d'actions:
Début ------------------------------------->
Fin <---------------------------------------

Note: La liste est vide.
Raison: Nous affichons le contenu du tableau avant d’avoir reçu la réponse de l’API.
Précédemment, l’exécution du programme bloquait à la lecture des données à partir d’Internet.
Maintenant, avec ‘ DispatchQueue.main.async ( execute: ‘, la lecture des données est faite en arrière plan et notre programme principal continu les traitements.

obtenirDonnéesDeMesActions()   // Envoyé en arrière plan
afficherDonnéesFinanceYahoo()  // *** N'attend plus après l'instruction précédente.

Avec cette technique, il faut traiter l’affichage des données et l’actualisation des composants MVC à l’intérieur du bloc de code du ‘dispatch’ (inline function, fonction anonyme).
De plus, dans ce bloc, les variables doivent-être précédées du mot clé  ‘self‘.  Par exemple,

self.donnéesFinanceYahoo = try! JSONDecoder().decode(YahooFinance.self, from: _data)
self.unTableView.reloadData()
self.nbLectures += 1
self.afficherDonnéesFinanceYahoo()

Action 6.6 – Retirer le commentaire suivant

// Action 6.6 - Retirer le commentaire suivant
// self.afficherDonnéesFinanceYahoo()

Action 6.7 – Tester l’application


6.8 Lire les données dans une boucle de temps

Action 6.9 – Retire le commentaire des lignes suivantes (3):

    func viewDidLoad() {
    ...
    // Timer.scheduledTimer(timeInterval: 10, target: self, selector: #selector(self.obtenirDonnéesDeMesActions), userInfo: nil, repeats: true)
    }
// Dans DispatchQueue.main.async :
// TODO: Action 6.9 - Enlever les commentaires à l'étape du 'timer'
// self.nbLectures += 1
// print("\n\n\(NSDate()) - Lecture numéro \(self.nbLectures)")

Action 6.10 – Tester l’application:

2017-10-28 15:56:33 +0000 - Lecture numéro 1
============================================
Voici les données du portefeuille d'actions:
Début ------------------------------------->
	MSFT: 84.00
	YHOO: Prix non disponible
	FB: 177.87
	INTC: 44.60
	HPQ: Prix non disponible
	AAPL: 162.94
	AMD: 11.84
	COKE: Prix non disponible
Fin <---------------------------------------
2017-10-28 15:56:43 +0000 - Lecture numéro 2
============================================
Voici les données du portefeuille d'actions:
Début ------------------------------------->
	MSFT: 83.75
	YHOO: Prix non disponible
	FB: 178.50
	INTC: 38.67
	HPQ: Prix non disponible
	AAPL: 162.99
	AMD: 11.80
	COKE: Prix non disponible
Fin <---------------------------------------

Note: la version finale est disponible via la branche ‘GCDFinale’


7 – Application de consultation du portefeuille d’actions

Action 7.1 – Passer à la branche ‘tableView‘ du projet Xcode.
Action 7.2 – Tester l’application
Action 7.3 – Analyser le code du projet


7.4 – Laboratoire à faire en classe

  1. Il faut remplacer les données du portefeuille ‘codées en dur’ par les données du fichier ‘portefeuille.json’
  2. Afficher dans la console,  la quantité d’actions, le prix de l’action, le total de la valeur (quant * prix) et la valeur du portefeuille. Attention, la quantité est optionnelle dans le fichier de données.
// Le fichier json
{
    "actions" : [
                 { "symbole" : "MSFT", "quant" : 5 },
                 { "symbole" : "FB", "quant" : 10 },
                 { "symbole" : "AAPL", "quant" : 25 },
                 { "symbole" : "AMD", "quant" : 50 },
                 { "symbole" : "MOMO" }
    ]
}

Résultat de la console:

============================================
Voici les données du portefeuille d'actions:
Début ------------------------------------->
	MSFT: 5 à 84.00 = 420.0
	FB: 10 à 177.87 = 1778.7
	AAPL: 25 à 162.94 = 4073.5
	AMD: 50 à 11.84 = 592.0
	MOMO: 0 à 30.54 = 0.0
La valeur du portefeuille est de 6864.2 $
Fin <---------------------------------------

Note: On charge un fichier json local, de la façon suivante:

if let _data = NSData(contentsOfFile: pathFichierPlist) as Data? {
  ...
}

Indice: Les actions seront à la même position dans le tableau du portefeuille et la tableau des données de Yahoo.


7.5 – Laboratoire à faire en classe

Choix 1 – Valeurs de conversion des devises en fonction du dollar américain.

Obtenir la valeur des monnaies en fonction de USD à partir de l’API suivante:
http://finance.yahoo.com/webservice/v1/symbols/allcurrencies/quote?format=json
Action: Écrire une application qui affiche, dans un UITableView, le Code (symbol) des devises ainsi que le prix (price).  Actualiser les données à chaque 15 secondes.

Choix 2 (défi plus élevé) – La température en temp réel de 10 villes 

Obtenir la température à partir de l’API suivante:
Température de 10 villes
Action: Écrire une application qui affiche, dans un UITableView, le nom de la ville ainsi que la température actuelle.  Actualiser les données à chaque 15 secondes.
Astuce: Pour consulter les données json en format structuré, copier le résultat json dans Brackets et afficher avec le plugin ‘Pretty Json’


Projet –  TIM.Ze.Game

Exemple d’un projet utilisant une libraire externe pour obtenir les images web.

Résultat final:


Mise en context:

Ce projet utilise un librairie externe pour la lecture des images à partir d’une URL;
SDWebImage disponible ici.
La librairie n’est pas incluse avec le projet, par contre, elle y est référée.
Il sera de la responsabilité de l’utilisateur d’ajouter les éléments manquants, requis pour le bon fonctionnement du projet.
Une façon simple est d’utiliser cocoapods
Voici: Une liste de librairies pour Xcode
Voici une autre liste :
https://medium.com/app-coder-io/33-ios-open-source-libraries-that-will-dominate-2017-4762cf3ce449
Voici un carrousel : https://github.com/nicklockwood/iCarousel
Un player video: https://github.com/mobileplayer/mobileplayer-ios


Installation d’un librairie via cocoapods

Comment?
1 – vérifier si cocoapods est installée sur votre poste en tapant ‘pod –version‘  dans la fenêtre terminal.
2 – Au besoin, il faudra l’installer:

$ sudo gem install cocoapods

ou par ‘homebrew

$ brew install cocoapods

3 – Dans le dossier de l’application, créer un fichier nommé ‘Podfile‘ renseignant les libraires à installer.
par exemple, pour le projet courant: Podfile

platform :ios, '8.0'
use_frameworks!
target 'MonDuProjet' do
	pod 'SDWebImage', '~> 4.0'
end

Voici un autre exemple

platform :ios, '8.0'
use_frameworks!
target 'MyApp' do
  pod 'AFNetworking', '~> 2.6'
  pod 'ORStackView', '~> 3.0'
  pod 'SwiftyJSON', '~> 2.3'
end

4 – Taper la commande suivante:

$ pod install

Note: La librairie devrait être installée et un espace de travail Xcode ‘xcworkspace’ créé.
5 – Ouvrir le projet en utilisant le fichier ‘nomDeApp.xcworkspace’

$ open App.xcworkspace

Exercice
1 – Créer un nouveau projet Xcode ‘testPod’.
2 – Fermer le projet
3 – Créer un nouveau fichier nommé ‘Podfile’ avec le contenu suivant – et enregistrer dans le dossier de l’application

platform :ios, '8.0'
use_frameworks!
target 'testPod' do
	pod 'SDWebImage', '~> 4.0'
end

4 – Ouvrir une fenêtre ‘terminal’ dans le dossier de l’application
5 – Exécuter la commande ‘$ pod install’
6 – Ouvrir le ‘workspace’


Action – Cloner le projet à l’adresse suivante:  https://github.com/ve2cuy/tim.ze.games.2017

$ git clone https://github.com/ve2cuy/tim.ze.games.2017 --branch versionFinale

 
Lien du projet sur GitHub: tim.ze.games
Version locale complète: tim.ze.games.v2017.01
Action – Analyse du projet – Suivre les directives en classe
Note: Ce projet présente, entre autre, des animations de propriétés ainsi que la lecture d’une trame sonore.
 


 

Autres APIs

Voici une liste d’APIs disponibles via le web:

Répertoire d’APIs web

http://www.programmableweb.com/apis/directory

Météo sur Yahoo

http://query.yahooapis.com/v1/public/yql?q=select%20item%20from%20weather.forecast%20where%20location%3D%22CAXX0301%22&format=json
Ce qui donne la météo pour Montréal (CAXX0301)
Voir:  http://developer.yahoo.com/yql/

Trouvez le UID d’une ville

http://wxdata.weather.com/wxdata/search/search?where=montr

Cotes de la bourse sur Yahoo

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&env=http%3A%2F%2Fdatatables.org%2Falltables.env&format=json
Ce qui donne les cotes de Yahoo,  d’Apple et d’Amazon et de microsoft.

Les taux de change

http://finance.yahoo.com/webservice/v1/symbols/allcurrencies/quote?format=json

tou.tv

http://api.tou.tv/v1/toutvapiservice.svc/json/GetPageRepertoire
Ce qui donne le répertoire de tou.tv
Voir:  https://code.google.com/p/tou-tv-for-boxee/wiki/Api

API Apple (iTune, app store, …)

http://www.apple.com/itunes/affiliates/resources/documentation/itunes-store-web-service-search-api.html

GiantBomb (jeux)

http://www.giantbomb.com/api/


Document par Alain Boudreault (c) 2016-2017