Lavorare con NSURLSession parte 3

Nei tutorial precedenti, abbiamo esplorato i fondamenti del NSURLSession API. C'è un'altra caratteristica del NSURLSession API che non abbiamo ancora esaminato, cioè caricamenti e download fuori processo. Nei prossimi due tutorial, ti mostrerò come creare un client per podcast molto semplice che abiliti i download in background.


introduzione

Il client podcast che stiamo per creare non sarà davvero funzionale. Permetterà all'utente di interrogare l'API di ricerca di iTunes per un elenco di podcast, selezionare un podcast e scaricare episodi. Dal momento che ci stiamo concentrando sul NSURLSession API, non andremo a riprodurre gli episodi dei download dell'applicazione.

Il progetto, tuttavia, ti insegnerà come utilizzare le attività di dati e le attività di download in un'applicazione reale. Il client podcast abiliterà anche i download in background per i quali faremo leva NSURLSessionL'API out-of-process. Abbiamo parecchie cose da fare quindi non perdiamo tempo e iniziamo.


1. Impostazione del progetto

Accendi Xcode 5, seleziona Nuovo> Progetto ... dal File menu e scegliere il Applicazione vista singola modello dall'elenco di modelli di applicazioni iOS. Dai un nome all'applicazione singlecast, impostare il Famiglia di dispositivi a i phone, e dire a Xcode dove vorresti salvare il progetto. Colpire Creare per creare il progetto.




2. Aggiorna Storyboard

La prima cosa che dobbiamo fare è modificare lo storyboard principale del progetto. Aperto Main.storyboard, seleziona l'unico controller di visualizzazione dello storyboard e scegli Incorporare in> Controller di navigazione dal editore menu. Il motivo per l'incorporamento del controller di visualizzazione in un controller di navigazione diventerà chiaro più avanti in questo tutorial.



3. Cerca Visualizza controller

Passaggio 1: creare file di classe

Come ho detto nell'introduzione, per mantenere le cose semplici, l'utente sarà in grado di iscriversi a un solo podcast. Iniziamo creando il controller della vista di ricerca. Selezionare Nuovo> File ... dal File menu e scegliere Classe Objective-C dalle opzioni a destra. Dai un nome alla classe MTSearchViewController e renderlo una sottoclasse di UIViewController. Lasciare la casella di controllo etichettata Con XIB per l'interfaccia utente incontrollato. Dillo a Xcode dove vuoi salvare i file di classe e colpire Creare.


Passaggio 2: interfaccia di classe di aggiornamento

Prima di creare l'interfaccia utente, aprire il file di intestazione del controller della vista e aggiornare l'interfaccia della classe come mostrato di seguito. Specifichiamo che il MTSearchViewController classe conforme al UITableViewDataSource, UITableViewDelegate, e UISearchBarDelegate protocolli, dichiariamo due punti vendita, barra di ricerca e tableView così come un'azione, Annulla, per chiudere il controller della vista di ricerca.

 #importare  @interface MTSearchViewController: UIViewController  @property (weak, nonatomic) IBOutlet UISearchBar * searchBar; @property (weak, nonatomic) IBOutlet UITableView * tableView; - (IBAction) cancel: (id) mittente; @fine

Passaggio 3: creare l'interfaccia utente

Rivisitare lo storyboard principale del progetto e trascinare un nuovo controller di visualizzazione dal Libreria di oggetti sulla destra. Seleziona il nuovo controller di visualizzazione, apri il Identity Inspector a destra e impostare la classe del controller di visualizzazione su MTSearchViewController. Con il nuovo controller di visualizzazione ancora selezionato, apri il editore menu e scegliere Incorporare in> Controller di navigazione. Trascina una vista tabella nella vista del controller della vista e connetti la vista tabella fonte di dati e delegare punti vendita con il controller della visualizzazione di ricerca.


Con la vista tabella ancora selezionata, apri il Ispettore degli attributi, e impostare il numero di celle prototipo in 1. Seleziona la cella prototipo e imposta la sua proprietà di stile a Sottotitolo e il suo identificativo a SearchCell.


Trascina una barra di ricerca da Libreria di oggetti e aggiungilo alla vista dell'intestazione della vista tabella. Seleziona la barra di ricerca e collegala delegare presa con il controller di visualizzazione.


Seleziona il controller della vista e collegalo barra di ricerca e tableView prese con la barra di ricerca e la vista tabella rispettivamente. Ci sono alcune altre cose che dobbiamo fare prima di aver finito con lo storyboard.

Apri il Libreria di oggetti e trascinare un elemento del pulsante della barra sulla barra di navigazione. Seleziona la voce del pulsante della barra, collegala con Annulla: azione che abbiamo dichiarato nell'interfaccia del controller della visualizzazione di ricerca e ne cambiamo l'aspetto Identifier nel Ispettore degli attributi a Annulla.


Trascina una voce del pulsante della barra sulla barra di navigazione del controller della vista (non sul controller della visualizzazione della ricerca) e modificala Identifier nel Ispettore degli attributi a Inserisci. Controlla il trascinamento dalla voce del pulsante della barra sul controller di navigazione del controller della ricerca e seleziona modale dal menu che si apre. Questo crea un seguito dal controller della vista al controller di navigazione del controller della ricerca.

Se dovessi controllare il trascinamento dalla voce del pulsante della barra del controller della vista direttamente al controller della vista di ricerca invece del suo controller di navigazione, il controller di navigazione non verrebbe mai istanziato e non vedresti una barra di navigazione nella parte superiore del controller della visualizzazione della ricerca.

Passaggio 4: implementazione della vista tabella

Prima di implementare il UITableViewDataSource e UITableViewDelegate protocolli nel MTSearchViewController classe, dobbiamo dichiarare una proprietà che memorizza i risultati di ricerca che otterremo dall'API di ricerca di iTunes. Assegna un nome alla proprietà podcast come mostrato di seguito. Dichiariamo anche una stringa statica che fungerà da identificatore di riutilizzo delle celle. Corrisponde all'identificatore che abbiamo impostato sulla cella del prototipo pochi istanti fa.

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

L'implementazione di numberOfSectionsInTableView: è facile come si arriva. Torniamo 1 Se self.podcasts non è zero e 0 se è. L'implementazione di tableView: numberOfRowsInSection: è abbastanza simile come puoi vedere qui sotto. Nel tableView: cellForRowAtIndexPath:, chiediamo la vista tabella per una cella passando l'identificatore di riutilizzo delle celle, che abbiamo dichiarato in precedenza, e indexPath. Prendiamo l'oggetto corrispondente dal podcast fonte di dati e aggiornare la cella di visualizzazione tabella. Tutti e due tableView: canEditRowAtIndexPath: e tableView: canMoveRowAtIndexPath: ritorno NO.

 - (NSInteger) numberOfSectionsInTableView: (UITableView *) tableView return self.podcasts? 1: 0; 
 - (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 forIndexPath: indexPath]; // Fetch Podcast NSDictionary * podcast = [self.podcasts objectAtIndex: indexPath.row]; // Configura cella Visualizza tabella [cell.textLabel setText: [podcast objectForKey: @ "collectionName"]]; [cell.detailTextLabel setText: [podcast objectForKey: @ "artistName"]]; cella di ritorno; 
 - (BOOL) tableView: (UITableView *) tableView canEditRowAtIndexPath: (NSIndexPath *) indexPath return NO; 
 - (BOOL) tableView: (UITableView *) tableView canMoveRowAtIndexPath: (NSIndexPath *) indexPath return NO; 

Prima di eseguire l'applicazione, implementare il Annulla: azione in cui ignoriamo il controller della vista di ricerca.

 - (IBAction) cancel: (id) sender [self dismissViewControllerAnimated: YES completion: nil]; 

Creare il progetto ed eseguire l'applicazione per assicurarsi che la base funzioni come previsto. È ora di iniziare a usare il NSURLSession API per interrogare l'API di ricerca di iTunes.

Passaggio 5: creazione di una sessione

Iniziamo dichiarando due proprietà private aggiuntive in MTSearchViewController classe, sessione e dataTask. Il sessione variabile è usata per memorizzare un riferimento al NSURLSession istanza che useremo per interrogare l'API di Apple. Manteniamo inoltre un riferimento all'attività dati che useremo per la richiesta. Questo ci consentirà di annullare l'attività di dati se l'utente aggiorna la query di ricerca prima che abbiamo ricevuto una risposta dall'API. Se hai un occhio per i dettagli, potresti aver notato che il MTSearchViewController la classe è anche conforme al UIScrollViewDelegate protocollo. La ragione di ciò diventerà chiara in pochi minuti.

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

La sessione viene creata nel suo metodo getter come puoi vedere di seguito. La sua implementazione non dovrebbe riservare sorprese se hai letto i tutorial precedenti. Escludiamo il metodo getter di sessione proprietà per caricare pigramente la sessione e limitare l'istanziazione e la configurazione della sessione nel suo metodo getter. Questo rende il codice pulito ed elegante.

 - (NSURLSession *) session if (! _Session) // Inizializza la configurazione della sessione NSURLSessionConfiguration * sessionConfiguration = [NSURLSessionConfiguration defaultSessionConfiguration]; // Configura configurazione sessione [sessionConfiguration setHTTPAdditionalHeaders: @ @ "Accept": @ "application / json"]; // Initialize Session _session = [NSURLSession sessionWithConfiguration: sessionConfiguration];  return _session; 

Passaggio 6: ricerca

Per rispondere all'input dell'utente nella barra di ricerca, implementiamo SearchBar: textDidChange: del UISearchBarDelegate protocollo. L'implementazione è semplice. Se Testo di ricerca è zero, il metodo torna presto. Se la lunghezza di Testo di ricerca è lungo meno di quattro caratteri, abbiamo ripristinato la ricerca invocando resetSearch. Se la query è di quattro caratteri o più, eseguiamo una ricerca chiamando performSearch sul controller della vista di ricerca.

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

Prima di ispezionare performSearch, diamo una rapida occhiata a resetSearch. Tutto ciò che facciamo resetSearch sta pulendo il contenuto di podcast e ricaricando la vista tabella.

 - (void) resetSearch // Aggiorna origine dati [self.podcasts removeAllObjects]; // Aggiorna tabella Visualizza [self.tableView reloadData]; 

Il sollevamento pesante è fatto in performSearch. Dopo aver memorizzato l'input dell'utente in una variabile denominata domanda, controlliamo se dataTask è impostato. Se è impostato, chiamiamo Annulla su di esso. Questo è importante in quanto non vogliamo ricevere una risposta da un vecchio richiesta che potrebbe non essere più rilevante per l'utente. Questo è anche il motivo per cui abbiamo una sola attività di dati attivi alla volta. Non vi è alcun vantaggio nell'invio di più richieste all'API.

Successivamente, chiediamo alla sessione una nuova istanza di attività dati facendola passare NSURL istanza e un gestore di completamento. Ricorda che la sessione è la fabbrica che crea attività. Non dovresti mai creare attività tu stesso. Se otteniamo un compito dati valido dalla sessione, chiamiamo curriculum vitae su di esso come abbiamo visto nelle precedenti esercitazioni.

La logica all'interno del gestore di completamento è a dir poco interessante. Il errore l'oggetto è importante per noi per diversi motivi. Non solo ci dirà se qualcosa è andato storto con la richiesta, ma è anche utile per determinare se l'attività di dati è stata annullata. Se otteniamo un oggetto di errore, controlliamo se il suo codice di errore è uguale a -999. Questo codice di errore indica che l'attività dati è stata annullata. Se otteniamo un altro codice di errore, registriamo l'errore nella console. In un'applicazione reale, è necessario migliorare la gestione degli errori e notificare all'utente quando viene generato un errore.

Se non è stato passato alcun errore al gestore di completamento, creiamo un dizionario dal NSData istanza che è stata passata al gestore di completamento e ne estrapiamo i risultati. Se abbiamo una serie di risultati con cui lavorare, passiamo a processResults:. Hai notato che abbiamo invocato processResults: in un blocco GCD (Grand Central Dispatch)? Perché l'abbiamo fatto? Spero che tu ricordi, perché è un dettaglio molto importante. Non abbiamo alcuna garanzia che il gestore di completamento sia invocato sul thread principale. Poiché dobbiamo aggiornare la vista tabella sul thread principale, dobbiamo assicurarci che processResults: è chiamato sul thread principale.

 - (void) performSearch NSString * query = self.searchBar.text; if (self.dataTask) [self.dataTask cancel];  self.dataTask = [self.session dataTaskWithURL: [self urlForQuery: query] completionHandler: ^ (dati NSData *, risposta NSURLResponse *, errore NSError *) if (errore) if (error.code! = -999)  NSLog (@ "% @", errore);  else NSDictionary * result = [NSJSONSerialization JSONObjectWithData: data options: 0 error: nil]; Risultati NSArray * = [risultato objectForKey: @ "risultati"]; dispatch_async (dispatch_get_main_queue (), ^ if (results) [self processResults: results];); ]; if (self.dataTask) [self.dataTask resume]; 

Prima di esaminare l'implementazione di processResults:, Voglio mostrarti rapidamente cosa succede dentro urlForQuery:, il metodo di supporto che usiamo performSearch. Nel urlForQuery:, sostituiamo qualsiasi spazio con a + firmare per assicurarsi che l'API di ricerca di iTunes sia felice di ciò che viene inviato. Quindi creiamo un NSURL istanza con esso e restituirlo.

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

Nel processResults:, il podcast la variabile viene cancellata, popolata con il contenuto di risultati, e i risultati vengono visualizzati nella vista tabella.

 - (void) processResults: (NSArray *) results if (! self.podcasts) self.podcasts = [NSMutableArray array];  // Aggiorna origine dati [self.podcasts removeAllObjects]; [self.podcasts addObjectsFromArray: risultati]; // Aggiorna tabella Visualizza [self.tableView reloadData]; 

Passaggio 6: selezione di un podcast

Quando l'utente tocca una riga nella vista tabella per selezionare un podcast, tableView: didSelectRowAtIndexPath: del UITableViewDelegate il protocollo è invocato. La sua implementazione può sembrare strana all'inizio, quindi lascia che ti spieghi cosa sta succedendo. Selezioniamo il podcast che corrisponde alla selezione dell'utente, lo memorizziamo nel database delle impostazioni predefinite dell'utente dell'applicazione e ignoriamo il controller della vista di ricerca. Non avvisiamo nessuno di questo? Perché lo facciamo diventerà chiaro una volta che continueremo ad implementare il MTViewController classe.

 - (void) tableView: (UITableView *) tableView didSelectRowAtIndexPath: (NSIndexPath *) indexPath [tableView deselectRowAtIndexPath: indexPath animato: YES]; // Fetch Podcast NSDictionary * podcast = [self.podcasts objectAtIndex: indexPath.row]; // Aggiorna utente Defatuls NSUserDefaults * ud = [NSUserDefaults standardUserDefaults]; [ud setObject: podcast forKey: @ "MTPodcast"]; [ud synchronize]; // Ignora controller vista [self dismissViewControllerAnimated: YES completion: nil]; 

Step 7: Tocchi finali

Ci sono due dettagli di cui voglio parlare prima di tornare al MTViewController classe. Quando il controller della vista di ricerca viene presentato all'utente, è chiaro che desidera cercare i podcast. È quindi consigliabile presentare immediatamente la tastiera. Lo facciamo dentro viewDidAppear: come mostrato di seguito.

 - (void) viewDidAppear: (BOOL) animato [super viewDidAppear: animato]; // Mostra tastiera [self.searchBar diventaFirstResponder]; 

La tastiera deve nascondersi nel momento in cui l'utente inizia a scorrere i risultati della ricerca. Per realizzare ciò, implementiamo scrollViewDidScroll: del UIScrollViewDelegate protocollo. Questo spiega perché MTSearchViewController conforme al UIScrollViewDelegate protocollo. Dai un'occhiata all'implementazione di scrollViewDidScroll: mostrato sotto.

 - (void) scrollViewDidScroll: (UIScrollView *) scrollView if ([self.searchBar isFirstResponder]) [self.searchBar resignFirstResponder]; 
Il UITableView la classe è una sottoclasse di UIScrollView, quale è la ragione per cui l'approccio sopra funziona.

4. Ripresa

Come abbiamo visto in precedenza, memorizziamo la selezione dell'utente nel database di default dell'utente dell'applicazione. Abbiamo bisogno di aggiornare il MTViewController classe per utilizzare la selezione dell'utente nel controller della visualizzazione di ricerca. Nel controller della vista viewDidLoad metodo, carichiamo il podcast dal database di default dell'utente e aggiungiamo il controller di visualizzazione come osservatore del database di default dell'utente per il percorso chiave MTPodcast in modo che al controller della vista venga notificato il valore per MTPodcast i cambiamenti.

 - (void) viewDidLoad [super viewDidLoad]; // Carica Podcast [auto loadPodcast]; // Aggiungi Observer [[NSUserDefaults standardUserDefaults] addObserver: self forKeyPath: @ Opzioni "MTPodcast": NSKeyValueObservingOptionNew context: NULL]; 

Tutto ciò che facciamo loadPodcast sta memorizzando il valore per MTPodcast dal database di default dell'utente nel controller della vista Podcast proprietà. Questo valore sarà zero se il database di default dell'utente non contiene una voce per MTPodcast. Il controller della vista gestirà con grazia questo per noi. Ricorda che, in Objective-C, puoi inviare messaggi a zero senza che si scateni l'inferno. Questo ha i suoi svantaggi, ma certamente ha i suoi vantaggi.

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

Ciò significa anche che dobbiamo dichiarare una proprietà denominata Podcast nel file di implementazione del controller della vista.

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

Diamo anche un'occhiata veloce setPodcast: e updateView.

 - (void) setPodcast: (NSDictionary *) podcast if (_podcast! = podcast) _podcast = podcast; // Aggiorna Visualizza [auto updateView]; 
 - (void) updateView // Aggiorna View self.title = [self.podcast objectForKey: @ "collectionName"]; 

Quando il valore nel database predefinito dell'utente cambia per la chiave MTPodcast, il controller della vista può rispondere a questo cambiamento observeValueForKeyPath: ofObject: cambiamento: contesto:. Ecco come funziona l'osservazione dei valori chiave. Tutto ciò che facciamo in questo metodo è l'aggiornamento del valore del controller della vista Podcast proprietà.

 - (void) observValueForKeyPath: (NSString *) keyPath ofObject: (id) modifica dell'oggetto: (NSDictionary *) modifica contesto: (void *) context if ([keyPath isEqualToString: @ "MTPodcast"]) self.podcast = [oggetto objectForKey: @ "MTPodcast"]; 

Quando si lavora con l'osservazione dei valori chiave, è fondamentale essere consapevoli della gestione della memoria e dei cicli di conservazione. In questo caso, significa che è necessario rimuovere il controller di visualizzazione come osservatore quando il controller di visualizzazione è deallocato.

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

5. Recupero e analisi del feed

Passaggio 1: aggiunta di dipendenze

La risposta che otteniamo dall'API di ricerca di iTunes include a feedUrl attributo per ogni podcast. Potremmo recuperare manualmente il feed e analizzarlo. Tuttavia, per risparmiare tempo, utilizzeremo MWFeedParser, una libreria popolare che può farlo per noi. Puoi scaricare e includere manualmente la libreria nel tuo progetto, ma opterò per Cocoapods. Preferisco Cocoapods per la gestione delle dipendenze nei progetti iOS e OS X. Puoi leggere ulteriori informazioni su Cocoapods sul suo sito web o su Mobiletuts+.

Ho intenzione di supporre che la gemma di Cocoapods sia installata sul tuo sistema. Puoi trovare istruzioni dettagliate in questo tutorial.

Esci da Xcode, vai alla radice del tuo progetto Xcode e crea un file chiamato Podfile. Apri questo file nel tuo editor di testo preferito e aggiungi le seguenti tre righe di codice. Nella prima riga, specifichiamo la piattaforma e l'obiettivo di distribuzione, che è iOS 7 in questo esempio. Le due righe successive specificano ciascuna una dipendenza del nostro progetto Xcode. Il primo è il MWFeedParser biblioteca e ho anche incluso il popolare SVProgressHUD libreria, che tornerà utile un po 'più tardi.

 piattaforma: ios, '7' pod 'MWFeedParser' pod 'SVProgressHUD'

Apri una finestra di Terminale, vai alla radice del tuo progetto Xcode ed esegui il comando installazione pod. Questo dovrebbe installare le dipendenze e creare uno spazio di lavoro Xcode. Quando Cocoapods ha finito di installare le dipendenze del progetto, ti dice di usare lo spazio di lavoro che ha creato per te. Questo è importante quindi non ignorare questo consiglio. Nella radice del tuo progetto Xcode, vedrai che Cocoapods ha davvero creato uno spazio di lavoro Xcode per te. Fai doppio clic su questo file e dovresti essere pronto per partire.


Passaggio 2: recupero e analisi del feed

Aprire il file di implementazione di MTViewController classe, aggiungere una dichiarazione di importazione per MWFeedParser e SVProgressHUD, e dichiarare due proprietà, Episodi e feedParser. Dobbiamo anche fare MTViewController conforme al MWFeedParserDelegate protocollo.

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

Successivamente, aggiorniamo setPodcast: invocando fetchAndParseFeed, un metodo di supporto in cui usiamo il MWFeedParser classe per recuperare e analizzare il feed del podcast.

 - (void) setPodcast: (NSDictionary *) podcast if (_podcast! = podcast) _podcast = podcast; // Aggiorna Visualizza [auto updateView]; // Fetch and Parse Feed [self fetchAndParseFeed]; 

Nel fetchAndParseFeed, ci liberiamo della nostra corrente MWFeedParser istanza se ne abbiamo uno e inizializzare una nuova istanza con l'URL del feed del podcast. Abbiamo impostato il feedParseType proprietà a ParseTypeFull e impostare il controller di visualizzazione come delegato del parser del feed. Prima di recuperare il feed, usiamo SVProgressHUD per mostrare un progresso HUD all'utente.

 - (void) fetchAndParseFeed if (! self.podcast) return; NSURL * url = [NSURL URLWithString: [self.podcast objectForKey: @ "feedUrl"]]; se (! url) ritorna; if (self.feedParser) [self.feedParser stopParsing]; [self.feedParser setDelegate: nil]; [self setFeedParser: nil];  // Cancella episodi if (self.episodes) [self setEpisodes: nil];  // Initialize Feed Parser self.feedParser = [[MWFeedParser alloc] initWithFeedURL: url]; // Configure Feed Parser [self.feedParser setFeedParseType: ParseTypeFull]; [self.feedParser setDelegate: self]; // Show Progress HUD [SVProgressHUD showWithMaskType: SVProgressHUDMaskTypeGradient]; // Inizia analisi [self.feedParser parse]; 

Dobbiamo anche implementare due metodi di MWFeedParserDelegate protocollo, feedParser: didParseFeedItem: e feedParserDidFinish:. Nel feedParser: didParseFeedItem:, inizializziamo il Episodi proprietà se necessario e passargli l'articolo del feed che il parser del feed ci fornisce.

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

Nel feedParserDidFinish:, ignoriamo l'HUD di avanzamento e aggiorniamo la vista tabella. Hai detto vista tabella? Giusto. Abbiamo bisogno di aggiungere una vista tabella e implementare il necessario UITableViewDataSource metodi di protocollo.

 - (void) feedParserDidFinish: (MWFeedParser *) parser // Ignora avanzamento HUD [SVProgressHUD respinto]; // Aggiorna Visualizza [self.tableView reloadData]; 

Passaggio 3: visualizzazione dell'alimentazione

Prima di aggiornare l'interfaccia utente, apri MTViewController.h, dichiarare uno sbocco per la vista tabella, e dire al compilatore il MTViewController classe conforme al UITableViewDataSource e UITableViewDelegate protocolli.

 #importare  @interface MTViewController: UIViewController  @property (weak, nonatomic) IBOutlet UITableView * tableView; @fine

Apri lo storyboard principale ancora una volta e aggiungi una vista tabella alla vista del controller della vista. Collega la vista tabella fonte di dati e delegare uscite con il controller di visualizzazione e collegare il controller di visualizzazione tableView presa con la vista tabella. Seleziona la vista tabella, apri il Ispettore degli attributi, e impostare il numero di celle prototipo in 1. Seleziona la cella prototipo, imposta il suo stile su Sottotitolo, e dargli un identificativo di EpisodeCell.


Prima di implementare il UITableViewDataSource protocollo, dichiarare una stringa statica chiamata EpisodeCell nel MTViewController.m. Ciò corrisponde all'identificatore che abbiamo impostato per la cella del prototipo nello storyboard.

 static NSString * EpisodeCell = @ "EpisodeCell";

Implementare il UITableViewDataSource il protocollo è semplice come una torta e molto simile a come abbiamo implementato il protocollo nel controller della vista di ricerca. L'unica differenza è che il Episodi variabile contiene istanze di MWFeedItem classe invece di NSDictionary casi.

 - (NSInteger) numberOfSectionsInTableView: (UITableView *) tableView return self.episodes? 1: 0; 
 - (NSInteger) tableView: (UITableView *) tableView numberOfRowsInSection: (NSInteger) section return self.episodes? self.episodes.count: 0; 
 - (UITableViewCell *) tableView: (UITableView *) tableView cellForRowAtIndexPath: (NSIndexPath *) indexPath UITableViewCell * cell = [tableView dequeueReusableCellWithIdentifier: EpisodeCell forIndexPath: indexPath]; // Recupera elemento feed MWFeedItem * feedItem = [self.episodes objectAtIndex: indexPath.row]; // Configura la cella Visualizza tabella [cell.textLabel setText: feedItem.title]; [cell.detailTextLabel setText: [NSString stringWithFormat: @ "% @", feedItem.date]]; cella di ritorno; 
 - (BOOL) tableView: (UITableView *) tableView canEditRowAtIndexPath: (NSIndexPath *) indexPath return NO; 
 - (BOOL) tableView: (UITableView *) tableView canMoveRowAtIndexPath: (NSIndexPath *) indexPath return NO; 

Esegui l'applicazione in iOS Simulator o su un dispositivo fisico ed eseguila attraverso i suoi passi. Ora dovresti essere in grado di cercare i podcast, selezionare un podcast dall'elenco e vedere i suoi episodi.


Conclusione

Abbiamo fatto molto in questo tutorial, ma abbiamo ancora un bel po 'di lavoro davanti a noi. Nel prossimo tutorial, ingrandiremo il download di episodi dal feed e discuteremo di download in background o out-of-process. Rimanete sintonizzati.