Travailler avec NSURLSession Partie 3

Dans les tutoriels précédents, nous avons exploré les principes fondamentaux de la NSURLSession API. Il y a une autre caractéristique de la NSURLSession API que nous n'avons pas encore examinée, à savoir les téléchargements et téléchargements hors processus. Dans les deux prochains tutoriels, je vais vous montrer comment créer un client de podcast très simple permettant des téléchargements en arrière-plan..


introduction

Le client de podcast que nous sommes sur le point de créer ne sera pas vraiment fonctionnel. Cela permettra à l'utilisateur d'interroger l'API de recherche iTunes pour obtenir une liste de podcasts, de sélectionner un podcast et de télécharger des épisodes. Puisque nous nous concentrons sur le NSURLSession API, nous n'allons pas lire les épisodes que l'application télécharge.

Le projet vous apprendra toutefois à utiliser des tâches de données et à télécharger des tâches dans une application réelle. Le client podcast activera également les téléchargements en arrière-plan pour lesquels nous allons tirer parti NSURLSessionL'API hors processus de. Nous avons pas mal de choses à faire, alors ne perdons pas de temps et commençons.


1. Configuration du projet

Lancez Xcode 5, sélectionnez Nouveau> Projet… du Fichier menu, et choisissez le Application à vue unique modèle dans la liste des modèles d'application iOS. Nommez l'application Singlecast, met le Famille de périphérique à iPhone, et indiquez à Xcode où vous souhaitez enregistrer le projet. Frappé Créer pour créer le projet.




2. Mise à jour du storyboard

La première chose à faire est de modifier le scénarimage principal du projet. Ouvrir Tableau principal, sélectionnez le seul contrôleur de vue du storyboard, puis choisissez Intégrer dans> Contrôleur de navigation du Éditeur menu. La raison de l'intégration du contrôleur de vue dans un contrôleur de navigation apparaîtra plus tard dans ce didacticiel..



3. Contrôleur de vue de recherche

Étape 1: Créer des fichiers de classe

Comme je l’ai mentionné dans l’introduction, pour simplifier les choses, l’utilisateur ne pourra s’abonner qu’à un seul podcast. Commençons par créer le contrôleur de vue de recherche. Sélectionner Nouveau> Fichier… du Fichier menu et choisir Classe Objective-C parmi les options à droite. Nommez la classe MTSearchViewController et en faire une sous-classe de UIViewController. Laissez la case à cocher intitulée Avec XIB pour l'interface utilisateur décoché. Indiquez à Xcode où vous souhaitez enregistrer les fichiers de classe et appuyez sur Créer.


Étape 2: Mise à jour de l'interface de classe

Avant de créer l'interface utilisateur, ouvrez le fichier d'en-tête du contrôleur de vue et mettez à jour l'interface de la classe, comme indiqué ci-dessous. Nous précisons que le MTSearchViewController classe conforme à la UITableViewDataSource, UITableViewDelegate, et UISearchBarDelegate protocoles, nous déclarons deux points de vente, barre de recherche et tableView ainsi qu'une action, Annuler, renvoyer le contrôleur de vue de recherche.

 #importation  @interface MTSearchViewController: UIViewController  @property (faible, non atomique) IBOutlet UISearchBar * searchBar; @property (faible, non atomique) IBOutlet UITableView * tableView; - (IBAction) cancel: (id) expéditeur; @fin

Étape 3: Créer une interface utilisateur

Revisitez le scénario principal du projet et faites glisser un nouveau contrôleur de vue du Bibliothèque d'objets sur la droite. Sélectionnez le nouveau contrôleur de vue, ouvrez le Inspecteur d'identité à droite, et définissez la classe du contrôleur de vue sur MTSearchViewController. Avec le nouveau contrôleur de vue toujours sélectionné, ouvrez le Éditeur menu et choisir Intégrer dans> Contrôleur de navigation. Faites glisser une vue tableau vers la vue du contrôleur de vue et connectez celle-ci la source de données et déléguer points de vente avec le contrôleur de vue de recherche.


La vue de tableau étant toujours sélectionnée, ouvrez le Inspecteur d'attributs, et définir le nombre de cellules prototypes à 1. Sélectionnez la cellule prototype et définissez sa propriété de style sur Sous-titre et son identifiant SearchCell.


Faites glisser une barre de recherche du Bibliothèque d'objets et l'ajouter à la vue en-tête de la vue tableau. Sélectionnez la barre de recherche et connectez son déléguer prise avec le contrôleur de vue.


Sélectionnez le contrôleur de vue et connectez son barre de recherche et tableView points de vente avec la barre de recherche et la vue tableau, respectivement. Il y a quelques autres choses que nous devons faire avant que nous ayons fini avec le storyboard.

Ouvrez le Bibliothèque d'objets et faites glisser un élément du bouton de la barre vers la barre de navigation. Sélectionnez le bouton barre, connectez-le avec le bouton Annuler: l'action que nous avons déclarée dans l'interface du contrôleur de vue de recherche, et changer son Identifiant dans le Inspecteur d'attributs à Annuler.


Faites glisser un élément de bouton dans la barre de navigation du contrôleur de vue (pas le contrôleur de recherche) et modifiez son Identifiant dans le Inspecteur d'attributs à Ajouter. Faites glisser le bouton de la barre vers le contrôleur de navigation du contrôleur de vue de recherche, puis sélectionnez modal dans le menu qui apparaît. Cela crée une transition entre le contrôleur de vue et le contrôleur de navigation du contrôleur de vue de recherche..

Si vous deviez contrôler le glissement du bouton de la barre du contrôleur de vue directement sur le contrôleur de vue de recherche au lieu de son contrôleur de navigation, le contrôleur de navigation ne serait jamais instancié et vous ne verriez pas de barre de navigation en haut du contrôleur de vue de recherche..

Étape 4: Mise en œuvre de la vue de table

Avant de mettre en œuvre le UITableViewDataSource et UITableViewDelegate protocoles dans le MTSearchViewController classe, nous devons déclarer une propriété qui stocke les résultats de la recherche que nous allons récupérer à partir de l’API de recherche iTunes. Nommez la propriété podcasts comme indiqué ci-dessous. Nous déclarons également une chaîne statique qui servira d'identifiant de réutilisation de cellule. Il correspond à l'identifiant que nous avons défini sur la cellule prototype il y a quelques instants..

 #import "MTSearchViewController.h" @interface MTSearchViewController () @property (strong, nonatomic) NSMutableArray * podcasts; @fin
 static NSString * SearchCell = @ "SearchCell";

L'implémentation de numberOfSectionsInTableView: est aussi facile que cela devient. Nous retournons 1 si self.podcasts n'est pas néant et 0 Si c'est. L'implémentation de tableView: numberOfRowsInSection: est assez similaire comme vous pouvez le voir ci-dessous. Dans tableView: cellForRowAtIndexPath:, nous demandons à la vue table pour une cellule en passant l'identifiant de réutilisation de la cellule, que nous avons déclaré précédemment, et indexPath. Nous allons chercher l'article correspondant à partir du podcasts source de données et mettre à jour la cellule de la vue tableau. Tous les deux tableView: canEditRowAtIndexPath: et tableView: canMoveRowAtIndexPath: revenir NON.

 - (NSInteger) numberOfSectionsInTableView: (UITableView *) tableView return self.podcasts? dix; 
 - (NSInteger) tableView: (UITableView *) tableView numberOfRowsInSection: (NSInteger) section return self.podcasts? self.podcasts.count: 0; 
 - (UITableViewCell *) tableView: (UITableView *) tableView cellForRowAtIndexPath: (NSIndexPath *) indexPath UITableViewCell * cell = [tableView dequeueReusableCellWithIdentifier: SearchCell pourIndexPath: indexPath]; // Récupérer le podcast NSDictionary * podcast = [self.podcasts objectAtIndex: indexPath.row]; // Configurer la cellule de la vue tableau [cell.textLabel setText: [podcast objectForKey: @ "collectionName"]]; [cell.detailTextLabel setText: [podcast objectForKey: @ "artistName"]]; cellule de retour; 
 - (BOOL) tableView: (UITableView *) tableView canEditRowAtIndexPath: (NSIndexPath *) indexPath return NO; 
 - (BOOL) tableView: (UITableView *) tableView canMoveRowAtIndexPath: (NSIndexPath *) indexPath return NO; 

Avant d’exécuter l’application, implémentez le Annuler: action dans laquelle nous rejetons le contrôleur de vue de recherche.

 - (IBAction) annuler: (id) expéditeur [auto-licenciement ViewControllerAnimated: YES complétion: nil]; 

Générez le projet et exécutez l'application pour vous assurer que la fondation fonctionne comme prévu. Il est temps de commencer à utiliser le NSURLSession API permettant d'interroger l'API iTunes Search.

Étape 5: Création d'une session

Commençons par déclarer deux propriétés privées supplémentaires dans le MTSearchViewController classe, session et dataTask. le session variable est utilisée pour stocker une référence à la NSURLSession exemple, nous utiliserons pour interroger l’API d’Apple. Nous conservons également une référence à la tâche de données que nous utiliserons pour la demande. Cela nous permettra d'annuler la tâche de données si l'utilisateur met à jour la requête de recherche avant que nous ayons reçu une réponse de l'API. Si vous avez le souci du détail, vous avez peut-être remarqué que le MTSearchViewController classe est également conforme à la UIScrollViewDelegate protocole. La raison de ceci deviendra claire dans quelques minutes.

 #import "MTSearchViewController.h" @interface MTSearchViewController ()  @property (strong, nonatomic) NSURLSession * session; @property (strong, nonatomic) NSURLSessionDataTask * dataTask; @property (strong, nonatomic) podcasts NSMutableArray *; @fin

La session est créée dans sa méthode de lecture, comme vous pouvez le voir ci-dessous. Son implémentation ne devrait pas vous surprendre si vous avez lu les tutoriels précédents. Nous substituons la méthode getter du session Cette propriété permet de charger paresseusement la session et de limiter l’instanciation et la configuration de la session dans sa méthode getter. Cela rend le code propre et élégant.

 - (NSURLSession *) session if (! _Session) // Initialiser la configuration de session NSURLSessionConfiguration * sessionConfiguration = [NSURLSessionConfiguration defaultSessionConfiguration]; // Configuration de la session [sessionConfiguration setHTTPAdditionalHeaders: @ @ "Accepter": @ "application / json"]; // Initialize Session _session = [NSURLSession sessionWithConfiguration: sessionConfiguration];  return _session; 

Étape 6: recherche

Pour répondre à la saisie de l'utilisateur dans la barre de recherche, nous implémentons Barre de recherche: textDidChange: du UISearchBarDelegate protocole. La mise en œuvre est simple. Si searchText est néant, la méthode revient tôt. Si la longueur de searchText est inférieure à quatre caractères, nous réinitialisons la recherche en appelant Réinitialiser la recherche. Si la requête comporte quatre caractères ou plus, nous effectuons une recherche en appelant performSearch sur le contrôleur de vue de recherche.

 - (void) searchBar: (UISearchBar *) searchBar textDidChange: (NSString *) searchText if (! searchText) return; si (searchText.length <= 3)  [self resetSearch];  else  [self performSearch];  

Avant que nous inspections performSearch, jetons un coup d'œil à Réinitialiser la recherche. Tout ce que nous faisons dans Réinitialiser la recherche efface le contenu de podcasts et recharger la vue table.

 - (void) resetSearch // Mettre à jour la source de données [self.podcasts removeAllObjects]; // Mise à jour de la vue de table [self.tableView reloadData]; 

Le levage de charges lourdes se fait en performSearch. Après avoir stocké l’entrée de l’utilisateur dans une variable nommée question, on vérifie si dataTask est réglé. Si elle est définie, nous appelons Annuler dessus. C’est important car nous ne voulons pas recevoir de réponse d’un vieux demande qui peut ne plus être pertinente pour l'utilisateur. C'est également la raison pour laquelle nous n'avons qu'une seule tâche de données active à la fois. Il n'y a aucun avantage à envoyer plusieurs requêtes à l'API..

Ensuite, nous demandons à la session une nouvelle instance de tâche de données en lui passant un NSURL instance et un gestionnaire d'achèvement. N'oubliez pas que la session est la fabrique qui crée les tâches. Vous ne devriez jamais créer de tâches vous-même. Si nous obtenons une tâche de données valide de la session, nous appelons CV sur ce que nous avons vu dans les tutoriels précédents.

La logique à l'intérieur du gestionnaire d'achèvement est pour le moins intéressante. le Erreur L'objet est important pour nous pour plusieurs raisons. Cela nous indiquera non seulement si quelque chose ne va pas avec la demande, mais cela est également utile pour déterminer si la tâche de données a été annulée. Si nous obtenons un objet d'erreur, nous vérifions si son code d'erreur est égal à -999. Ce code d'erreur indique que la tâche de données a été annulée. Si nous obtenons un autre code d'erreur, nous enregistrons l'erreur dans la console. Dans une application réelle, vous devez améliorer la gestion des erreurs et avertir l'utilisateur lorsqu'une erreur est générée..

Si aucune erreur n'a été transmise au gestionnaire d'achèvement, nous créons un dictionnaire à partir du NSData exemple qui a été passé au gestionnaire d’achèvement et nous en extrayons les résultats. Si nous avons un tableau de résultats à utiliser, nous le transmettons à processResults:. Avez-vous remarqué que nous avons invoqué processResults: dans un bloc GCD (Grand Central Dispatch)? Pourquoi avons-nous fait ça? J'espère que vous vous en souvenez, car c'est un détail très important. Nous n'avons aucune garantie que le gestionnaire d'achèvement soit appelé sur le thread principal. Puisque nous devons mettre à jour la vue de table sur le fil principal, nous devons nous assurer que processResults: est appelé sur le fil principal.

 - (void) performSearch NSString * query = self.searchBar.text; if (self.dataTask) [self.dataTask cancel];  self.dataTask = [self.session dataTaskWithURL: [self urlForQuery: query] completionHandler: ^ (données NSData *, réponse NSURLResponse *, erreur NSError *) if (erreur) if (error.code! = -999)  NSLog (@ "% @", erreur);  else NSDictionary * result = [NSJSONSerialization JSONObjectWithData: options de données: 0 erreur: nil]; NSArray * results = [result objectForKey: @ "results"]; dispatch_async (dispatch_get_main_queue (), ^ if (résultats) [self processResults: results];); ]; if (self.dataTask) [self.dataTask resume]; 

Avant de regarder la mise en œuvre de processResults:, Je veux vous montrer rapidement ce qui se passe dans urlForQuery:, la méthode d'assistance que nous utilisons dans performSearch. Dans urlForQuery:, nous remplaçons les espaces par un + signez pour vous assurer que l'API iTunes Search est satisfait de ce que nous l'envoyons. Nous créons ensuite un NSURL par exemple avec et le retourner.

 - (NSURL *) urlForQuery: (NSString *) requête requête = [requête stringByReplacingOcurrencesOfString: @ "" withString: @ "+"]; return [NSURL URLWithString: [NSString stringWithFormat: @ "https://itunes.apple.com/search?media=podcast&entity=podcast&term=%@", requête]]; 

Dans processResults:, la podcasts la variable est effacée, renseignée avec le contenu de résultats, et les résultats sont affichés dans la vue tableau.

 - (void) processResults: (NSArray *) résultats if (! self.podcasts) self.podcasts = [tableau NSMutableArray];  // Mettre à jour la source de données [self.podcasts removeAllObjects]; [self.podcasts addObjectsFromArray: results]; // Mise à jour de la vue de table [self.tableView reloadData]; 

Étape 6: Sélection d'un podcast

Lorsque l'utilisateur appuie sur une ligne de la vue tableau pour sélectionner un podcast, tableView: didSelectRowAtIndexPath: du UITableViewDelegate le protocole est appelé. Sa mise en œuvre peut sembler étrange au début, alors laissez-moi vous expliquer ce qui se passe. Nous sélectionnons le podcast qui correspond à la sélection de l'utilisateur, nous l'enregistrons dans la base de données par défaut de l'application et nous rejetons le contrôleur de vue de recherche. Nous n'en informons personne? Pourquoi nous faisons cela deviendra clair une fois que nous continuerons à mettre en œuvre les MTViewController classe.

 - (void) tableView: (UITableView *) tableView didSelectRowAtIndexPath: (NSIndexPath *) indexPath [tableView deselectRowAtIndexPath: indexPath animé: YES]; // Récupérer le podcast NSDictionary * podcast = [self.podcasts objectAtIndex: indexPath.row]; // Mise à jour des valeurs utilisateur NSUserDefaults * ud = [NSUserDefaults standardUserDefaults]; [ud setObject: podcast forKey: @ "MTPodcast"]; [ud synchronize]; // Dismiss View Controller [autoJViewViewControllerAnimated: YES complétion: nil]; 

Étape 7: Touches finales

Je veux parler de deux détails avant de revenir à la MTViewController classe. Lorsque le contrôleur de vue de recherche est présenté à l'utilisateur, il est clair qu'il souhaite rechercher des podcasts. C'est donc une bonne idée de présenter immédiatement le clavier. Nous faisons cela dans viewDidAppear: comme indiqué ci-dessous.

 - (void) viewDidAppear: (BOOL) animated [super viewDidAppear: animated]; // Afficher le clavier [self.searchBar devientFirstResponder]; 

Le clavier doit masquer le moment où l'utilisateur commence à faire défiler les résultats de la recherche. Pour ce faire, nous mettons en œuvre scrollViewDidScroll: du UIScrollViewDelegate protocole. Ceci explique pourquoi MTSearchViewController conforme à la UIScrollViewDelegate protocole. Regardez l'implémentation de scrollViewDidScroll: indiqué ci-dessous.

 - (void) scrollViewDidScroll: (UIScrollView *) scrollView if ([self.searchBar isFirstResponder]) self.searchBar resignFirstResponder]; 
le UITableView classe est une sous-classe de UIScrollView, quelle est la raison pour laquelle l'approche ci-dessus fonctionne.

4. boucle arrière

Comme nous l'avons vu précédemment, nous stockons la sélection de l'utilisateur dans la base de données par défaut de l'application. Nous devons mettre à jour le MTViewController classe pour utiliser la sélection de l'utilisateur dans le contrôleur de vue de recherche. Dans le contrôleur de vue viewDidLoad méthode, nous chargeons le podcast à partir de la base de données par défaut de l'utilisateur et ajoutons le contrôleur de vue en tant qu'observateur de la base de données par défaut de l'utilisateur pour le chemin d'accès à la clé MTPodcast de sorte que le contrôleur de vue soit averti lorsque la valeur de MTPodcast changements.

 - (void) viewDidLoad [super viewDidLoad]; // Chargement du podcast [self loadPodcast]; // Add Observer [[NSUserDefaults standardUserDefaults] addObserver: self forKeyPath: @ options "MTPodcast": NSKeyValueObservingOptionNew context: NULL]; 

Tout ce que nous faisons dans loadPodcast stocke la valeur pour MTPodcast à partir de la base de données par défaut de l'utilisateur dans le contrôleur de vue Podcast propriété. Cette valeur sera néant si la base de données par défaut de l'utilisateur ne contient pas d'entrée pour MTPodcast. Le contrôleur de vue gérera cela avec élégance pour nous. Rappelez-vous qu’en Objective-C, vous pouvez envoyer des messages à néant sans que l'enfer se déchaîne. Cela a ses inconvénients, mais il a certainement ses avantages à.

 - (void) loadPodcast NSUserDefaults * ud = [NSUserDefaults standardUserDefaults]; self.podcast = [ud objectForKey: @ "MTPodcast"]; 

Cela signifie également que nous devons déclarer une propriété nommée Podcast dans le fichier d'implémentation du contrôleur de vue.

 #import "MTViewController.h" @interface MTViewController () @property (strong, nonatomic) NSDictionary * podcast; @fin

Regardons aussi rapidement setPodcast: et updateView.

 - (void) setPodcast: (NSDictionary *) podcast if (_podcast! = podcast) _podcast = podcast; // Mise à jour de la vue [self updateView]; 
 - (void) updateView // Vue de la mise à jour self.title = [self.podcast objectForKey: @ "nom de la collection"]; 

Lorsque la valeur dans la base de données utilisateur par défaut change pour la clé MTPodcast, le contrôleur de vue peut répondre à ce changement de observeValueForKeyPath: ofObject: change: context:. C'est ainsi que l'observation des valeurs clés fonctionne. Tout ce que nous faisons dans cette méthode est de mettre à jour la valeur du contrôleur de vue Podcast propriété.

 - (void) observeValueForKeyPath: (NSString *) keyPath ofObject: (id) modification d'objet: (NSDictionary *) changement de contexte: (void *) contexte if ([keyPath isEqualToString: @ "MTPodcast"]) self.podcast = [object objectForKey: @ "MTPodcast"]; 

Lorsque vous utilisez l'observation des valeurs clés, il est essentiel de prendre conscience de la gestion de la mémoire et de conserver les cycles. Dans ce cas, cela signifie que nous devons supprimer le contrôleur de vue en tant qu'observateur lorsque le contrôleur de vue est désalloué..

 - (void) dealloc [[[NSUserDefaults standardUserDefaults]] removeObserver: self forKeyPath: @ "MTPodcast"]; 

5. Récupération et analyse du flux

Étape 1: Ajout de dépendances

La réponse que nous recevons de l’API de recherche iTunes inclut un URL du flux attribut pour chaque podcast. Nous pourrions récupérer le flux manuellement et l’analyser. Cependant, pour gagner du temps, nous allons utiliser MWFeedParser, une bibliothèque populaire qui peut le faire pour nous. Vous pouvez télécharger et inclure manuellement la bibliothèque dans votre projet, mais je vais opter pour les Cocoapods. Je préfère les Cocoapods pour la gestion des dépendances dans les projets iOS et OS X. Vous pouvez en savoir plus sur Cocoapods sur son site web ou sur Mobiletuts+.

Je vais supposer que la gemme Cocoapods est installée sur votre système. Vous pouvez trouver des instructions détaillées dans ce tutoriel.

Quittez Xcode, accédez à la racine de votre projet Xcode et créez un fichier nommé Podfile. Ouvrez ce fichier dans l'éditeur de texte de votre choix et ajoutez les trois lignes de code suivantes. Dans la première ligne, nous spécifions la plate-forme et la cible de déploiement, qui est iOS 7 dans cet exemple. Les deux lignes suivantes spécifient chacune une dépendance de notre projet Xcode. Le premier est le MWFeedParser bibliothèque et j'ai aussi inclus le populaire SVProgressHUD bibliothèque, qui sera utile un peu plus tard.

 plate-forme: ios, '7' pod 'MWFeedParser' pod 'SVProgressHUD'

Ouvrez une fenêtre de terminal, accédez à la racine de votre projet Xcode et exécutez la commande installation de pod. Cela devrait installer les dépendances et créer un espace de travail Xcode.. Lorsque Cocoapods a fini d’installer les dépendances du projet, il vous indique d’utiliser l’espace de travail qu’il a créé pour vous. Ceci est important alors n'ignore pas ce conseil. À la racine de votre projet Xcode, vous verrez que Cocoapods a en effet créé un espace de travail Xcode pour vous. Double-cliquez sur ce fichier et vous devriez être prêt à partir.


Étape 2: Récupération et analyse du flux

Ouvrez le fichier d'implémentation du MTViewController classe, ajoutez une déclaration d'importation pour MWFeedParser et SVProgressHUD, et déclarer deux propriétés, épisodes et feedParser. Nous devons aussi faire MTViewController se conformer à la MWFeedParserDelegate protocole.

 #import "MTViewController.h" #import "MWFeedParser.h" #import "SVProgressHUD.h" @interface MTViewController ()  @property (strong, nonatomic) NSDictionary * podcast; @property (strong, nonatomic) épisodes NSMutableArray *; @property (strong, nonatomic) MWFeedParser * feedParser; @fin

Ensuite, nous mettons à jour setPodcast: en invoquant fetchAndParseFeed, une méthode d'assistance dans laquelle nous utilisons le MWFeedParser classe pour récupérer et analyser le flux du podcast.

 - (void) setPodcast: (NSDictionary *) podcast if (_podcast! = podcast) _podcast = podcast; // Mise à jour de la vue [self updateView]; // Récupération et analyse de flux [self fetchAndParseFeed]; 

Dans fetchAndParseFeed, nous nous débarrassons de notre courant MWFeedParser exemple si nous en avons un et initialisons une nouvelle instance avec l’URL du flux du podcast. Nous avons mis le feedParseType propriété à ParseTypeFull et définissez le contrôleur de vue en tant que délégué de l'analyseur de flux. Avant de récupérer le flux, nous utilisons SVProgressHUD montrer un progrès à l'utilisateur.

 - (void) fetchAndParseFeed if (! self.podcast) return; NSURL * url = [NSURL URLWithString: [self.podcast objectForKey: @ "feedUrl"]]; si (! url) retourne; if (self.feedParser) [self.feedParser stopParsing]; [self.feedParser setDelegate: nil]; [self setFeedParser: nil];  // Effacer les épisodes if (self.episodes) [self setEpisodes: nil];  // Initialisation de l'analyseur de flux self.feedParser = [[MWFeedParser alloc]] initWithFeedURL: url]; // Configurer l'analyseur de flux [self.feedParser setFeedParseType: ParseTypeFull]; [self.feedParser setDelegate: self]; // Afficher la palette de progression [SVProgressHUD showWithMaskType: SVProgressHUDMaskTypeGradient]; // Démarrer l'analyse [self.feedParser parse]; 

Nous devons également mettre en œuvre deux méthodes de MWFeedParserDelegate protocole, feedParser: didParseFeedItem: et feedParserDidFinish:. Dans feedParser: didParseFeedItem:, on initialise le épisodes propriété si nécessaire et transmettez-lui l'élément de fil que l'analyseur de flux nous tend.

 - (void) feedParser: (MWFeedParser *) analyseur didParseFeedItem: (MWFeedItem *) item if (! self.episodes) self.episodes = [tableau NSMutableArray];  [self.episodes addObject: item]; 

Dans feedParserDidFinish:, nous rejetons le HUD de progression et mettons à jour la vue tableau. Avez-vous dit vue de la table? C'est vrai. Nous devons ajouter une vue de table et mettre en œuvre le nécessaire UITableViewDataSource méthodes de protocole.

 - (void) feedParserDidFinish: (MWFeedParser *) parser // Refuser le HUD de progression [SVProgressHUD ignorer]; // Mise à jour de la vue [self.tableView reloadData]; 

Étape 3: Affichage du flux

Avant de mettre à jour l'interface utilisateur, ouvrez MTViewController.h, déclarez un point de vente pour la vue table et dites au compilateur le MTViewController classe conforme à la UITableViewDataSource et UITableViewDelegate les protocoles.

 #importation  @interface MTViewController: UIViewController  @property (faible, non atomique) IBOutlet UITableView * tableView; @fin

Ouvrez le scénario principal une fois de plus et ajoutez une vue tabulaire à la vue du contrôleur de vue. Connecter la vue de la table la source de données et déléguer prises avec le contrôleur de vue et connecter le contrôleur de vue tableView sortie avec la vue de la table. Sélectionnez la vue tableau, ouvrez le Inspecteur d'attributs, et définir le nombre de cellules prototypes à 1. Sélectionnez la cellule prototype, définissez son style sur Sous-titre, et lui donner un identifiant de EpisodeCell.


Avant de mettre en œuvre le UITableViewDataSource protocole, déclarer une chaîne statique nommée EpisodeCell dans MTViewController.m. Cela correspond à l'identifiant que nous avons défini pour la cellule prototype dans le storyboard..

 static NSString * EpisodeCell = @ "EpisodeCell";

Mise en œuvre du UITableViewDataSource Le protocole est simple comme bonjour et très similaire à la façon dont nous avons implémenté le protocole dans le contrôleur de vue de recherche. La seule différence est que le épisodes la variable contient des occurrences du MWFeedItem classe au lieu de NSDictionary les instances.

 - (NSInteger) numberOfSectionsInTableView: (UITableView *) tableView return self.episodes? dix; 
 - (NSInteger) tableView: (UITableView *) table numéroViewOfRowsInSection: (NSInteger) section return self.episodes? self.episodes.count: 0; 
 - (UITableViewCell *) tableView: (UITableView *) tableView cellForRowAtIndexPath: (NSIndexPath *) indexPath UITableViewCell * cell = [tableView dequeueReusableCellWithIdentifier: EpisodeCell pourIndexPath: indexPath]; // Récupération d'un élément de fil MWFeedItem * feedItem = [self.episodes objectAtIndex: indexPath.row]; // Configure Table View Cell [cell.textLabel setText: feedItem.title]; [cell.detailTextLabel setText: [NSString stringWithFormat: @ "% @", feedItem.date]]; cellule de retour; 
 - (BOOL) tableView: (UITableView *) tableView canEditRowAtIndexPath: (NSIndexPath *) indexPath return NO; 
 - (BOOL) tableView: (UITableView *) tableView canMoveRowAtIndexPath: (NSIndexPath *) indexPath return