{"id":252,"date":"2013-10-17T14:32:39","date_gmt":"2013-10-17T18:32:39","guid":{"rendered":"http:\/\/tim.cstj.qc.ca\/cours\/xcode\/wp\/?page_id=252"},"modified":"2013-10-17T14:32:39","modified_gmt":"2013-10-17T18:32:39","slug":"rottentomatoes","status":"publish","type":"page","link":"https:\/\/ve2cuy.com\/xcode\/labo\/rottentomatoes\/","title":{"rendered":"Les rottentomatoes"},"content":{"rendered":"<h1>Utilisation d&rsquo;une &lsquo;API&rsquo; web<\/h1>\n<p>Dans le tutoriel <a href=\"http:\/\/tim.cstj.qc.ca\/xcode\/index.php\/labo\/timflix-delegation-et-uitableview-personnalisee\/\">TIMFlix<\/a>, nous avons construit une application qui affichait une liste de vid\u00e9os \u00e0 l&rsquo;int\u00e9rieur d&rsquo;un UITableView. \u00a0Les 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:<\/p>\n<ul>\n<li>obtenir des informations sur des films \u00e0 partir du web en utilisant l&rsquo;API du site <a href=\"http:\/\/www.rottentomatoes.com\/\">www.rottentomatoes.com<\/a>.<\/li>\n<li>rendre les requ\u00eates sur Internet non bloquantes pour notre application.<\/li>\n<\/ul>\n<p>&nbsp;<br \/>\n<div id=\"attachment_260\" style=\"width: 219px\" class=\"wp-caption alignleft\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-260\" class=\" wp-image-260\" style=\"margin-right: 50px;\" src=\"\/xcode\/wp-content\/uploads\/\/2013\/10\/tomato1.png\" alt=\"tomato1\" width=\"209\" height=\"219\" \/><p id=\"caption-attachment-260\" class=\"wp-caption-text\">voir note au bas<\/p><\/div><br \/>\nPr\u00e9-requis:<\/p>\n<ol>\n<li>Avoir compl\u00e9t\u00e9 le tutoriel <a href=\"http:\/\/tim.cstj.qc.ca\/xcode\/index.php\/labo\/timflix-delegation-et-uitableview-personnalisee\/\">TIMFlix<\/a>\u00a0ou bien avoir une maitrise de l&rsquo;objet UITableView + segue + passage de param\u00e8tres entre les sc\u00e8nes d&rsquo;une app.<\/li>\n<li>S&rsquo;inscrire sur le site de <a href=\"http:\/\/developer.rottentomatoes.com\/member\/register\">rottentomatoes<\/a><\/li>\n<li>Obtenir une cl\u00e9\u00a0<a href=\"http:\/\/developer.rottentomatoes.com\/apps\/register\">d\u00e9veloppeur<\/a><\/li>\n<\/ol>\n<p>&nbsp;<br \/>\n&nbsp;<br \/>\n&nbsp;<br \/>\nVid\u00e9o du r\u00e9sultat final:<br \/>\nhttp:\/\/www.youtube.com\/watch?v=LBi6Z0RnINM<br \/>\n&nbsp;<\/p>\n<hr \/>\n<p>&nbsp;<\/p>\n<h1>API de rottenTomatoes<\/h1>\n<p>&nbsp;<br \/>\nLe site &lsquo;RottenTomatoes&rsquo; propose une API d&rsquo;acc\u00e8s aux donn\u00e9es qu&rsquo;il compile. \u00a0Ces donn\u00e9es nous renseignent sur des films, \u00a0les critiques, les acteurs, les personnages, &#8230;<br \/>\n&nbsp;<br \/>\nPour interroger l&rsquo;api de\u00a0rottentomatoes, il suffit de suivre l&rsquo;URL suivante:<br \/>\n&nbsp;<\/p>\n<blockquote><p>http:\/\/api.rottentomatoes.com\/api\/public\/v1.0\/movies.json?apikey=<span style=\"color: #ff0000;\">VOTRECLE<\/span>&amp;q=<span style=\"color: #ff0000;\">MODELE_DE_RECHERCHE<\/span>&amp;page_limit=<span style=\"color: #ff0000;\">NB_PAGES<\/span><\/p><\/blockquote>\n<p>&nbsp;<br \/>\nComme par exemple,\u00a0http:\/\/api.rottentomatoes.com\/api\/public\/v1.0\/movies.json?apikey=<span style=\"color: #ff0000;\">ax2345bv67ncs2734<\/span>&amp;q=<span style=\"color: #ff0000;\">Star<\/span>&amp;page_limit=<span style=\"color: #ff0000;\">10<\/span><br \/>\nNote: La cl\u00e9 de l&rsquo;exemple est invalide. \u00a0Vous devez la remplacer par celle que vous avez obtenue de rottentomatoes.\u00a0\u00a0La limite de pages fix\u00e9e par l&rsquo;api est de 50 pages.<br \/>\nLa requ\u00eate pr\u00e9c\u00e9dente devrait nous retourner une structure JSON contenant une liste d&rsquo;au plus 10 films dont la cha\u00eene &lsquo;Star&rsquo; appara\u00eet dans le titre du film.<br \/>\nPour obtenir, \u00e0 partir du r\u00e9seau Internet, des donn\u00e9es en format JSON et cr\u00e9er un dictionnaire, il faut utiliser la syntaxe suivante:<\/p>\n<blockquote><p>donnesViaURL = [NSData dataWithContentsOfURL:[NSURL URLWithString:adresseURL]];<br \/>\nNSError *error;<br \/>\nstructureJSONConvertie = [NSJSONSerialization JSONObjectWithData:donnesViaURL options:kNilOptions error:&amp;error];<\/p><\/blockquote>\n<p>&nbsp;<\/p>\n<hr \/>\n<p>&nbsp;<\/p>\n<h2>\u00c9tape 1<\/h2>\n<p><span style=\"color: #ff0000;\"><strong>ACTION<\/strong><\/span> &#8211; Ouvrons le projet de <a href=\"https:\/\/docs.google.com\/uc?export=download&amp;id=0Bxk2a0khnQQ7RmpyY1dYSG05RkE\">d\u00e9part<\/a> et ajoutons le code suivant \u00e0 la m\u00e9thode &lsquo;rechercherFilms&rsquo; de la classe contr\u00f4leur de la sc\u00e8ne principale.<br \/>\n&nbsp;<\/p>\n<pre class=\"toolbar:1 lang:default decode:true\">\/\/  ViewController.m\n\/\/ --------------------------------------------------------\n-(BOOL) rechercherFilms:(NSString *) film\n\/\/ --------------------------------------------------------\n\/\/  Description:  M\u00e9thode qui ...\n{\n    \/\/ Construire l'URL pointant sur l'API\n    NSString * URLFilm = [NSString stringWithFormat:@\"http:\/\/api.rottentomatoes.com\/api\/public\/v1.0\/movies.json?apikey=%@&amp;q=%@&amp;page_limit=%@\", CLE_API,film, NB_FILMS];\n    \/\/ Obtenir les donn\u00e9es en format brut\n    NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:URLFilm]];\n    \/\/ Si data est vide alors quitter la m\u00e9thode\n    if (!data) { NSLog(@\"URL n'a pas retourn\u00e9 de donn\u00e9es!\"); return NO;}\n    \/\/ Convertir les donn\u00e9es brutes en format JSON et les placer\n    \/\/ dans tableauDesFilms\n    NSError *error;\n    tableauDesFilms = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:&amp;error];\n    \/\/ V\u00e9rifier si la conversion a fonctionn\u00e9\n    if (!tableauDesFilms) {\n        NSLog(@\"Pour une raison \u00e9trange, la requ\u00eate chez 'rottentomatoes' a retourn\u00e9e une structure JSON mal form\u00e9e...\");\n        return NO;\n    }\n    NSLog(@\"tableauDesFilms = %@\", tableauDesFilms);\n    self.nbResultat.text = [NSString stringWithFormat:@\"%d\", ((NSArray*)tableauDesFilms[@\"movies\"]).count];\n    return YES;\n} \/\/ FIN -&gt; rechercherFilms<\/pre>\n<p>&nbsp;<br \/>\n&nbsp;<br \/>\n<span style=\"color: #ff0000;\"><strong>ACTION<\/strong><\/span> &#8211; \u00a0Testons l&rsquo;application. \u00a0Remarquez que la m\u00e9thode &lsquo;rechercherFilm&rsquo; est appel\u00e9e dans &lsquo;viewDidLoad&rsquo;.<br \/>\n&nbsp;<br \/>\n<a href=\"\/xcode\/wp-content\/uploads\/\/2013\/10\/rotten-001.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-558\" src=\"\/xcode\/wp-content\/uploads\/\/2013\/10\/rotten-001.png\" alt=\"rotten-001\" width=\"1286\" height=\"1062\" \/><\/a><br \/>\n&nbsp;<br \/>\nNous devrions obtenir le r\u00e9sultat suivant dans la zone &lsquo;debug\u00a0\u00bb \u00a0d&rsquo;Xcode:<br \/>\n&nbsp;<\/p>\n<pre class=\"toolbar:1 lang:default decode:true\"> tableauDesFilms = {\n    \"link_template\" = \"http:\/\/api.rottentomatoes.com\/api\/public\/v1.0\/movies.json?q={search-term}&amp;page_limit={results-per-page}&amp;page={page-number}\";\n    links =     {\n        next = \"http:\/\/api.rottentomatoes.com\/api\/public\/v1.0\/movies.json?q=star&amp;page_limit=1&amp;page=2\";\n        self = \"http:\/\/api.rottentomatoes.com\/api\/public\/v1.0\/movies.json?q=star&amp;page_limit=1&amp;page=1\";\n    };\n    movies =     (  \/\/  &lt;-- tableau de films\n                {   \/\/  &lt;-- dictionnaire de donn\u00e9es du premier film de la liste\n            \"abridged_cast\" =             (\n                                {\n                    characters =                     (\n                        \"Anakin Skywalker\/Darth Vader\"\n                    );\n                    id = 162652153;\n                    name = \"Hayden Christensen\";\n                },\n                                {\n                    characters =                     (\n                        \"Obi-Wan Kenobi\"\n                    );\n                    id = 162652152;\n                    name = \"Ewan McGregor\";\n                },\n                                {\n                    characters =                     (\n                        \"R2-D2\"\n                    );\n                    id = 418638213;\n                    name = \"Kenny Baker\";\n                },\n                                {\n                    characters =                     (\n                        \"Ruwee Naberrie\"\n                    );\n                    id = 548155708;\n                    name = \"Graeme Blundell\";\n                },\n                                {\n                    characters =                     (\n                        \"Captain Colton\"\n                    );\n                    id = 358317901;\n                    name = \"Jeremy Bulloch\";\n                }\n            );\n            \"alternate_ids\" =             {\n                imdb = 0121766;\n            };\n            \"critics_consensus\" = \"This sixth and final installment of George Lucas' epic space opera will please die-hard fanatics and non-believers alike -- largely due to awesome digital effects and the sheer power of the mythology.\";\n            id = 9;\n            links =             {\n                alternate = \"http:\/\/www.rottentomatoes.com\/m\/star_wars_episode_iii_revenge_of_the_sith_3d\/\";\n                cast = \"http:\/\/api.rottentomatoes.com\/api\/public\/v1.0\/movies\/9\/cast.json\";\n                clips = \"http:\/\/api.rottentomatoes.com\/api\/public\/v1.0\/movies\/9\/clips.json\";\n                reviews = \"http:\/\/api.rottentomatoes.com\/api\/public\/v1.0\/movies\/9\/reviews.json\";\n                self = \"http:\/\/api.rottentomatoes.com\/api\/public\/v1.0\/movies\/9.json\";\n                similar = \"http:\/\/api.rottentomatoes.com\/api\/public\/v1.0\/movies\/9\/similar.json\";\n            };\n            \"mpaa_rating\" = \"PG-13\";\n            posters =             {\n                detailed = \"http:\/\/content8.flixster.com\/movie\/10\/94\/47\/10944718_det.jpg\";\n                original = \"http:\/\/content8.flixster.com\/movie\/10\/94\/47\/10944718_ori.jpg\";\n                profile = \"http:\/\/content8.flixster.com\/movie\/10\/94\/47\/10944718_pro.jpg\";\n                thumbnail = \"http:\/\/content8.flixster.com\/movie\/10\/94\/47\/10944718_mob.jpg\";\n            };\n            ratings =             {\n                \"audience_rating\" = Upright;\n                \"audience_score\" = 65;\n                \"critics_rating\" = \"Certified Fresh\";\n                \"critics_score\" = 80;\n            };\n            \"release_dates\" =             {\n                dvd = \"2005-11-01\";\n            };\n            runtime = 140;\n            synopsis = \"\";\n            title = \"Star Wars: Episode III - Revenge of the Sith 3D\";\n            year = 2005;  \/\/ &lt;-- date du premier film de la liste\n        },  \/\/ &lt;-- fin des donn\u00e9es du premier film de la liste\n               {  \/\/ &lt;-- deuxi\u00e8me film de la liste\n            \"abridged_cast\" =             ();\n            ...\n            \"mpaa_rating\" = \"PG-13\";\n            posters =             {\n                original = \"http:\/\/content9.flixster.com\/movie\/11\/17\/38\/11173843_ori.jpg\";\n            };\n            runtime = 127;\n            synopsis = \"\";\n            title = \"Star Trek\";\n            year = 2009;\n        },\n        ...\n    );\n    total = 1319;\n}<\/pre>\n<p>&nbsp;<br \/>\nEn analysant la structure pr\u00e9c\u00e9dente, il est possible d&rsquo;\u00e9noncer les <a href=\"http:\/\/fr.wikipedia.org\/wiki\/Axiome\">axiomes<\/a>\u00a0suivants:<\/p>\n<ol>\n<li>Le dictionnaire contient un tableau de films \u00e0 l&rsquo;\u00e9l\u00e9ment dictionnaire[@\u00a0\u00bbmovies\u00a0\u00bb].<\/li>\n<li>Toutes les informations d&rsquo;un film sont disponibles \u00e0 dictionnaire[@\u00a0\u00bbmovies\u00a0\u00bb][indiceDuFilm].<\/li>\n<li>\u00a0[@\u00a0\u00bbmovies\u00a0\u00bb][indiceDuFilm] retourne un dictionnaire<\/li>\n<li>Une information sur un film est disponible \u00e0\u00a0dictionnaire[@\u00a0\u00bbmovies\u00a0\u00bb][indiceDuFilm] [@\u00a0\u00bbnomChamp\u00a0\u00bb].<\/li>\n<\/ol>\n<p>Ainsi, pour obtenir la date du premier film de la liste nous \u00e9crirons:<\/p>\n<blockquote><p>\u00a0dateDuPremierFilm =\u00a0dictionnaire[@\u00a0\u00bbmovies\u00a0\u00bb][0][@\u00a0\u00bbyear\u00a0\u00bb]<\/p><\/blockquote>\n<p><strong>QUESTION<\/strong>: \u00a0Comment obtenir l&rsquo;affiche originale du deuxi\u00e8me film?<br \/>\n&nbsp;<br \/>\n<strong>ACTION<\/strong> &#8211; Affichons le titre des films re\u00e7us (\u00e0 la fin de la m\u00e9thode: &lsquo;rechercherFilms&rsquo;)<br \/>\n:<\/p>\n<pre class=\"toolbar:1 lang:default decode:true\">\/\/ Corriger l'erreur avec une signature pour tableauDesFilms[@\"movies\"]\n  for (int i = 0 ; i&lt; tableauDesFilms[@\"movies\"].count; i++){\n        NSLog(@\"Titre %d = %@\", i, tableauDesFilms[@\"movies\"][i][@\"title\"]);\n}<\/pre>\n<p>&nbsp;<br \/>\n&nbsp;<\/p>\n<hr \/>\n<h2>\u00c9tape 2 &#8211; Actualiser la requ\u00eate suite \u00e0 &lsquo;textFieldShouldReturn&rsquo;<\/h2>\n<p>&nbsp;<br \/>\nRemarquer qu&rsquo;il y a une zone de recherche en haut \u00e0 droite de l&rsquo;application. \u00a0Nous allons utiliser la m\u00e9thode de d\u00e9l\u00e9gation &lsquo;textFieldShouldReturn&rsquo; du &lsquo;UITextField&rsquo;\u00a0\u00a0pour relancer la requ\u00eate vers l&rsquo;api de rottenTomatoes.<br \/>\n&nbsp;<br \/>\n<a href=\"\/xcode\/wp-content\/uploads\/\/2013\/10\/rotten-002.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-562\" src=\"\/xcode\/wp-content\/uploads\/\/2013\/10\/rotten-002.png\" alt=\"rotten-002\" width=\"269\" height=\"71\" \/><\/a><br \/>\n&nbsp;<br \/>\n<span style=\"color: #ff0000;\"><strong>ACTION<\/strong><\/span> &#8211; Ajoutons le code suivant \u00e0 la m\u00e9thode &lsquo;textFieldShouldReturn&rsquo;\u00a0de la classe contr\u00f4leur de la sc\u00e8ne principale.<br \/>\n&nbsp;<\/p>\n<pre class=\"lang:default decode:true\">- (BOOL)textFieldShouldReturn:(UITextField *)textField{\n    \/\/ Convertir la chaine en format 'escaped' pour le web, par exemple, remplacer les espaces par %20, ...\n    NSString *escapedText = [textField.text stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];\n    NSLog(@\"escapedText = %@\", escapedText);\n    \/\/ Relancer la requete vers rottenTomatoes\n    [self rechercherFilms:escapedText];\n    \/\/ Actualiser les cellules du UICollectionView\n    [self.collectionDeFilms reloadData];\n    \/\/ Arreter l'animation de progression\n    [self.progression stopAnimating];\n    [textField resignFirstResponder];\n    return YES;\n}<\/pre>\n<p>&nbsp;<br \/>\n<span style=\"color: #ff0000;\"><strong>ACTION<\/strong><\/span> &#8211; Rempla\u00e7ons \u00a0la trace sur le titre des films par le code suivant (m\u00e9thode &lsquo;rechercherFilms&rsquo;). \u00a0Nous allons ici, utiliser l&rsquo;\u00e9num\u00e9ration rapide pour parcourir les \u00e9l\u00e9ments de &lsquo;tableauDesFilms[@\u00a0\u00bbmovies\u00a0\u00bb]&rsquo;.<br \/>\n&nbsp;<\/p>\n<pre class=\"lang:default decode:true\">-(BOOL) rechercherFilms:(NSString *) film\n...\n    \/\/ Afficher le titre de tous les films trouv\u00e9s\n    for (NSDictionary * film in tableauDesFilms[@\"movies\"]) {\n        NSLog(@\"Titre = %@\", film[@\"title\"]);\n    }\n return ...<\/pre>\n<p>&nbsp;<br \/>\n<span style=\"color: #ff0000;\"><strong>ACTION<\/strong><\/span> &#8211; Testons l&rsquo;application<br \/>\n&nbsp;<br \/>\nhttp:\/\/www.youtube.com\/watch?v=SgfEfEuKYrU<br \/>\n&nbsp;<\/p>\n<hr \/>\n<h2>\u00c9tape 3 &#8211; Renseigner les UICollectionViewCell<\/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>[UIImage imageNamed:@\u00a0\u00bbpochette.jpg\u00a0\u00bb];<\/p><\/blockquote>\n<p>Mais lorsque que ce fichier est stock\u00e9 dans le r\u00e9seau Internet il faut proc\u00e9der ainsi:<\/p>\n<blockquote><p>[UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:urlImage]]]<\/p><\/blockquote>\n<p>Note: La qualit\u00e9 de l&rsquo;exp\u00e9rience utilisateur va \u00eatre affect\u00e9e par le\u00a0chargement d&rsquo;un grand nombre d&rsquo;images. \u00a0Plus tard, nous vous proposerons une solution \u00e0 ce probl\u00e8me.<br \/>\n&nbsp;<br \/>\n<span style=\"color: #ff0000;\"><strong>ACTION<\/strong><\/span> &#8211; \u00a0Ajoutons le code suivant \u00e0 la m\u00e9thode &lsquo;cellForItem&#8230;&rsquo; du fichier ViewController.m\u00a0\u00bb<br \/>\n&nbsp;<\/p>\n<pre class=\"toolbar:1 lang:default mark:11,15 decode:true\">\/\/  ViewController.m\n- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{\n    CelluleRotten * celluleCourante = [collectionView dequeueReusableCellWithReuseIdentifier:@\"modeleCellule\" forIndexPath:indexPath];\n    NSString * urlImage = tableauDesFilms[@\"movies\"][indexPath.row][@\"posters\"][@\"original\"];\n    \/\/ Cette op\u00e9ration est tr\u00e8s bloquante!!!\n    \/\/ Charger une image \u00e0 partir du web\n    \/\/ \u00c0 compl\u00e9ter ...\n    celluleCourante.filmImage.image = [UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:urlImage]]];\n    \/\/ Renseigner le titre du film\n    \/\/ \u00c0 compl\u00e9ter ...\n    celluleCourante.titre.text = tableauDesFilms[@\"movies\"][indexPath.row][@\"title\"];\n    return celluleCourante;\n}<\/pre>\n<p>&nbsp;<br \/>\n<span style=\"color: #ff0000;\"><strong>ACTION<\/strong><\/span> &#8211; Corrigeons la valeur de retour de \u00a0la m\u00e9thode &lsquo;numberOfItems&#8230;&rsquo;<br \/>\n&nbsp;<\/p>\n<pre class=\"toolbar:1 lang:default mark:2 decode:true\">- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {\n    return ((NSArray*)tableauDesFilms[@\"movies\"]).count;\n}<\/pre>\n<p>&nbsp;<br \/>\n<span style=\"color: #ff0000;\"><strong>ACTION<\/strong><\/span> &#8211; Ajoutons le code suivant \u00e0 la m\u00e9thode &lsquo;prepareForSegue&rsquo;<br \/>\n&nbsp;<\/p>\n<pre class=\"toolbar:1 lang:default mark:7 decode:true\">\/\/  ViewController.m\n\/\/ Passer les info \u00e0 la sc\u00e8ne de d\u00e9tail\n-(void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender   {\n    DetailFilmViewController * vc = [segue destinationViewController];\n    \/\/ Passer les informations de la section courant \u00e0 la sc\u00e8ne de d\u00e9tail\n    \/\/ \u00c0 compl\u00e9ter...\n    vc.detailFilm = tableauDesFilms[@\"movies\"][[[self.ViewVideos indexPathForCell:sender] row]];\n}<\/pre>\n<p>&nbsp;<br \/>\n<span style=\"color: #ff0000;\"><strong>ACTION<\/strong><\/span> &#8211; \u00a0Augmentons le nombre maximum de films pour la requ\u00eate vers l&rsquo;api de rottenTomatoes<br \/>\n&nbsp;<\/p>\n<pre class=\"toolbar:1 lang:default mark:2 decode:true\">\/\/  ViewController.h\n#define NB_FILMS @\"50\"<\/pre>\n<p>&nbsp;<br \/>\n<span style=\"color: #ff0000;\"><strong>ACTION<\/strong><\/span> &#8211; Testons l&rsquo;application. \u00a0<span style=\"color: #ff0000;\">Vous allez remarquer un important manque de r\u00e9ponse de l&rsquo;application.<\/span><br \/>\n&nbsp;<br \/>\nhttp:\/\/www.youtube.com\/watch?v=bsFFn6ULjyI<br \/>\n&nbsp;<br \/>\n<a href=\"https:\/\/docs.google.com\/uc?export=download&amp;id=0Bxk2a0khnQQ7THkxejdNSHp1TUE\">T\u00e9l\u00e9charger le projet \u00e0 cette \u00e9tape<\/a><br \/>\n&nbsp;<\/p>\n<hr \/>\n<h2>\u00c9tape 4 &#8211; Am\u00e9liorer l&rsquo;exp\u00e9rience utilisateur<\/h2>\n<p>&nbsp;<br \/>\nPr\u00e9sentement, les requ\u00eates web de l&rsquo;application sont bloquantes, C-A-D que l&rsquo;application attend la r\u00e9ponse de la requ\u00eate avant de passer \u00e0 la ligne de code suivante. \u00a0Cela a pour effet de bloquer aussi l&rsquo;interactivit\u00e9 de l&rsquo;application.<br \/>\nLe &lsquo;framework&rsquo; cocoa nous propose l&rsquo;objet &lsquo;<strong>NSURLConnection<\/strong>&lsquo; et la m\u00e9thode suivante pour lancer une requ\u00eate web non bloquante:<\/p>\n<blockquote><p>\u00a0[NSURLConnection<br \/>\n<span style=\"color: #ff0000;\">\u00a0 \u00a0sendAsynchronousRequest<\/span>:UneRequete<br \/>\n<span style=\"color: #ff0000;\">\u00a0 \u00a0queue<\/span>: uneFileExecution<span style=\"color: #ff0000;\"><br \/>\ncompletionHandler<\/span>:UnBlocDeCodeAExecuter \u00a0\/\/ \u00e0 la r\u00e9ception des donn\u00e9es<br \/>\n]<\/p><\/blockquote>\n<p>&nbsp;<br \/>\nPr\u00e9sentement, nous utilisons la syntaxe suivante pour lancer une requ\u00eate vers l&rsquo;api de rottenTomatoes:<br \/>\n&nbsp;<\/p>\n<pre class=\"toolbar:1 lang:default mark:4 decode:true\">...\n\/\/ Obtenir les donn\u00e9es en format brut\nNSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:URLFilm]];\n...\n\/\/ Convertir les donn\u00e9es brutes en format JSON\ntableauDesFilms = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:&amp;error];\n...<\/pre>\n<p>&nbsp;<br \/>\n<span style=\"font-size: 13px; line-height: 19px;\">\u00a0<span style=\"color: #ff0000;\"><strong>ACTION<\/strong><\/span> &#8211; Modifions la m\u00e9thode &lsquo;rechercherFilms&rsquo; pour rendre la requ\u00eate non bloquante<\/span><\/p>\n<pre class=\"lang:default decode:true\">\/\/  ViewController.m\n\/\/ --------------------------------------------------------\n-(BOOL) rechercherFilms:(NSString *) film\n\/\/ --------------------------------------------------------\n\/\/  Description:  M\u00e9thode qui ...\n{\n    [self.progression startAnimating];\n    NSString * adresseURL = [NSString stringWithFormat:@\"http:\/\/api.rottentomatoes.com\/api\/public\/v1.0\/movies.json?apikey=%@&amp;q=%@&amp;page_limit=%@\", CLE_API,film, NB_FILMS];\n    \/\/ Requete via URL non bloquante\n    [NSURLConnection sendAsynchronousRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:adresseURL]]\n                                       queue:[NSOperationQueue currentQueue]\n                           completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {\n                               if (!error) { NSLog(@\"Requete = succes\");\n                                   tableauDesFilms = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:&amp;error];\n                                   self.nbResultat.text = [NSString stringWithFormat:@\"%d\",((NSArray*)tableauDesFilms[@\"movies\"]).count];\n                                   [self.collectionDeFilms reloadData];\n                                   [self.progression stopAnimating];\n                               } else {\n                                   NSLog(@\"Oups, probl\u00e8me avec la requ\u00eate web, erreur = %@\", error);\n                               } \/\/ FIN -&gt; if, else\n                           }  \/\/ FIN -&gt; completionHandler\n     ];\n    return YES;\n} \/\/ FIN -&gt; rechercherFilms<\/pre>\n<p>&nbsp;<br \/>\n<span style=\"color: #ff0000;\"><strong>ACTION<\/strong><\/span> &#8211; Testons l&rsquo;application.<br \/>\nVous allez remarquer que la sc\u00e8ne principale est affich\u00e9e imm\u00e9diatement. \u00a0 Pr\u00e9c\u00e9demment, la sc\u00e8ne \u00e9tait affich\u00e9e suite au traitement de la requ\u00eate web qui bloquait l&rsquo;ex\u00e9cution de l&rsquo;application.<br \/>\nPar contre, le chargement des pochettes de films est encore bloquant.<br \/>\nUtilisons la m\u00eame technique pour charger les images via le r\u00e9seau Internet.<br \/>\n&nbsp;<br \/>\n<span style=\"color: #ff0000;\"><strong>ACTION<\/strong><\/span> &#8211; Dans la m\u00e9thode &lsquo;<strong>cellForItemAtIndexPath<\/strong>&lsquo;, rempla\u00e7ons la ligne de code \u00a0qui charge l&rsquo;image via une URL par:<br \/>\n&nbsp;<\/p>\n<pre class=\"toolbar:1 lang:default mark:6 decode:true\">\/\/  ViewController.m\n- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{\n...\n    \/\/ Cette op\u00e9ration n'est plus bloquante!!!\n    \/\/ Charger une image \u00e0 partir du web\n    \/\/  celluleCourante.filmImage.image = [UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:urlImage]]];\n    NSMutableURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:urlImage]];\n    celluleCourante.filmImage.image = [UIImage imageNamed:@\"loading.gif\"];\n    [NSURLConnection sendAsynchronousRequest:request\n                                       queue:[NSOperationQueue mainQueue]\n                           completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {\n                               if ( !error )\n                               {\n                                   celluleCourante.filmImage.image = [[UIImage alloc] initWithData:data];\n                               }\n                           }];\n...\n}<\/pre>\n<p>&nbsp;<br \/>\n<span style=\"color: #ff0000;\"><strong>ACTION<\/strong><\/span> &#8211; \u00c0 vous de modifier la classe de la sc\u00e8ne &lsquo;d\u00e9tail&rsquo; pour que le chargement des quatre affiches ne soit plus bloquant.<br \/>\n&nbsp;<br \/>\n<a href=\"https:\/\/docs.google.com\/uc?export=download&amp;id=0Bxk2a0khnQQ7LXVsUXVwaS1YQVE\">T\u00e9l\u00e9charger le projet termin\u00e9\u00a0<\/a><br \/>\n&nbsp;<\/p>\n<hr \/>\n<h1>Autres APIs<\/h1>\n<p>&nbsp;<br \/>\nVoici une liste d&rsquo;APIs disponibles via le web:<br \/>\n&nbsp;<\/p>\n<h2>R\u00e9pertoire d&rsquo;APIs web<\/h2>\n<p><a href=\"http:\/\/www.programmableweb.com\/apis\/directory\">http:\/\/www.programmableweb.com\/apis\/directory<\/a><br \/>\n&nbsp;<\/p>\n<h2>M\u00e9t\u00e9o sur Yahoo<\/h2>\n<p><a href=\"http:\/\/query.yahooapis.com\/v1\/public\/yql?q=select%20item%20from%20weather.forecast%20where%20location%3D%22CAXX0301%22&amp;format=json\">http:\/\/query.yahooapis.com\/v1\/public\/yql?q=select%20item%20from%20weather.forecast%20where%20location%3D%22<span style=\"color: #ff0000;\">CAXX0301<\/span>%22&amp;format=json<\/a><br \/>\nCe qui donne la m\u00e9t\u00e9o pour Montr\u00e9al (CAXX0301)<br \/>\nVoir: \u00a0<a href=\"http:\/\/developer.yahoo.com\/yql\/\">http:\/\/developer.yahoo.com\/yql\/<\/a><br \/>\n&nbsp;<\/p>\n<h2>Cotes de la bourse sur Yahoo<\/h2>\n<p><a href=\"http:\/\/query.yahooapis.com\/v1\/public\/yql?q=select%20*%20from%20yahoo.finance.quotes%20where%20symbol%20in%20%28%22AAPL,AMZN%22%29&amp;env=store:\/\/datatables.org\/alltableswithkeys&amp;format=json\">http:\/\/query.yahooapis.com\/v1\/public\/yql?q=select%20*%20from%20yahoo.finance.quotes%20where%20symbol%20in%20%28%22<span style=\"color: #ff0000;\">AAPL,AMZN<\/span>%22%29&amp;env=store:\/\/datatables.org\/alltableswithkeys&amp;format=json<\/a><br \/>\nCe qui donne les cotes d&rsquo;Apple et Amazon<br \/>\n&nbsp;<\/p>\n<h2>tou.tv<\/h2>\n<p><a href=\"http:\/\/api.tou.tv\/v1\/toutvapiservice.svc\/json\/GetPageRepertoire\"><span style=\"font-size: 13px; line-height: 19px;\">http:\/\/api.tou.tv\/v1\/toutvapiservice.svc\/json\/GetPageRepertoire<\/span><\/a><br \/>\n<span style=\"font-size: 13px; line-height: 19px;\">Ce qui donne le r\u00e9pertoire de tou.tv<\/span><br \/>\nVoir: \u00a0<a href=\"https:\/\/code.google.com\/p\/tou-tv-for-boxee\/wiki\/Api\">https:\/\/code.google.com\/p\/tou-tv-for-boxee\/wiki\/Api<\/a><br \/>\n&nbsp;<\/p>\n<h2>GiantBomb (jeux)<\/h2>\n<p><a href=\"http:\/\/www.giantbomb.com\/api\/\">http:\/\/www.giantbomb.com\/api\/<\/a><\/p>\n<hr \/>\n<p><span style=\"font-size: 0.75em; line-height: 19px;\">Note: \u00a0L&rsquo;image sur cette page est la propri\u00e9t\u00e9 intellectuelle de\u00a0Flixster.<\/span><br \/>\n&nbsp;<br \/>\n&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Utilisation d&rsquo;une &lsquo;API&rsquo; web Dans le tutoriel TIMFlix, nous avons construit une application qui affichait une liste de vid\u00e9os \u00e0 l&rsquo;int\u00e9rieur d&rsquo;un UITableView. \u00a0Les informations des vid\u00e9os, ainsi que l&rsquo;image des affiches, \u00e9taient renseign\u00e9es localement grace \u00e0 un fichier de propri\u00e9t\u00e9s. L&rsquo;inconv\u00e9nient de cette approche est \u00e9vident lorsque vient le temps d&rsquo;y ajouter de nouvelles [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"parent":26,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"footnotes":""},"class_list":["post-252","page","type-page","status-publish","hentry"],"_links":{"self":[{"href":"https:\/\/ve2cuy.com\/xcode\/wp-json\/wp\/v2\/pages\/252","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=252"}],"version-history":[{"count":0,"href":"https:\/\/ve2cuy.com\/xcode\/wp-json\/wp\/v2\/pages\/252\/revisions"}],"up":[{"embeddable":true,"href":"https:\/\/ve2cuy.com\/xcode\/wp-json\/wp\/v2\/pages\/26"}],"wp:attachment":[{"href":"https:\/\/ve2cuy.com\/xcode\/wp-json\/wp\/v2\/media?parent=252"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}