Lucrul cu NSURLSession Partea 3

În tutorialele anterioare, am explorat fundamentele NSURLSession API-ul. Există o altă caracteristică a NSURLSession API pe care nu am analizat încă, adică încărcări și descărcări în afara procesului. În următoarele două tutoriale, vă voi arăta cum să creați un client podcast foarte simplu, care să permită descărcarea fundalului.


Introducere

Clientul podcast pe care urmează să-l creăm nu va fi într-adevăr funcțional. Acesta va permite utilizatorului să interogheze API-ul iTunes Search pentru o listă de podcast-uri, să selecteze un podcast și să descarce episoade. Deoarece ne concentrăm pe NSURLSession API, nu vom intra în redarea episoadelor descărcărilor aplicațiilor.

Proiectul, cu toate acestea, vă va învăța cum să utilizați sarcinile de date și să descărcați sarcini într-o aplicație din lumea reală. Clientul podcast va permite, de asemenea, descărcări de fundal pentru care le vom folosi NSURLSession's out-of-process API. Avem foarte puține lucruri pentru a face acest lucru, să nu pierdem timpul și să începem.


1. Configurarea proiectului

Activați Xcode 5, selectați Nou> Proiect ... de la Fişier meniu și alegeți Vizualizare individuală șablon din lista de șabloane de aplicații iOS. Denumiți aplicația Singlecast, Seteaza Familia de dispozitive la iPhone, și spuneți Xcode unde doriți să salvați proiectul. Lovit Crea pentru a crea proiectul.




2. Actualizați Storyboard

Primul lucru pe care trebuie să-l facem este să editați tabloul de bord principal al proiectului. Deschis Main.storyboard, selectați controlerul vizualizării numai de la panoul de afișare și alegeți Încorporați în> Controller de navigare de la Editor meniul. Motivul pentru încorporarea controlerului de vizualizare într-un controler de navigație va deveni clar mai târziu în acest tutorial.



3. Controller vizualizare căutare

Pasul 1: Creați fișiere de clasă

După cum am menționat în introducere, pentru a menține lucrurile simple, utilizatorul va putea abona la un singur podcast. Să începem prin crearea controlerului de vizualizare a căutării. Selectați Nou> Fișier ... de la Fişier meniu și alegeți Clasa obiectiv-C din opțiunile din dreapta. Denumiți clasa MTSearchViewController și să o facă o subclasă de UIViewController. Lăsați caseta de selectare etichetă Cu XIB pentru interfața cu utilizatorul neverificată. Spuneți Xcode unde doriți să salvați fișierele de clasă și să le loviți Crea.


Pasul 2: Actualizarea interfeței de clasă

Înainte de a crea interfața cu utilizatorul, deschideți fișierul de antet al controlerului de vizualizare și actualizați interfața clasei așa cum se arată mai jos. Specificăm că MTSearchViewController clasa este conformă cu UITableViewDataSource, UITableViewDelegate, și UISearchBarDelegate protocoale, declarăm două puncte de vânzare, bara de căutare și tableView precum și o acțiune, Anulare, să respingă controlerul de vizualizare a căutării.

 #import  @interface MTSearchViewController: UIViewController  @property (slab, nonatomic) IBOutlet UISearchBar * searchBar; @property (slab, nonatomic) IBOutlet UITableView * tableView; - (IBAction) anulați: (id) expeditor; @Sfârșit

Pasul 3: Creați o interfață utilizator

Revizuiți tabloul de bord al proiectului și trageți un nou controler de vizualizare din Biblioteca de obiecte pe dreapta. Selectați noul controler de vizualizare, deschideți Inspectorul de identitate din dreapta, și setați clasa controlerului de vizualizare la MTSearchViewController. Cu noul controler de vizualizare selectat, deschideți Editor meniu și alegeți Încorporați în> Controller de navigare. Glisați o vizualizare de tabelă în vizualizarea controlerului de vizualizare și conectați vizualizarea tabelului sursă de date și delega punctele de vânzare cu controler vizualizare căutare.


Cu ecranul de masă selectat încă, deschideți Atribuții Inspector, și setați numărul de celule prototip 1. Selectați celula prototip și setați proprietatea stilului la Subtitlu și identificatorul său la SearchCell.


Glisați o bară de căutare din Biblioteca de obiecte și adăugați-l în vizualizarea antetului tabelului. Selectați bara de căutare și conectați-o delega priza cu controlerul de vizualizare.


Selectați controlerul de vizualizare și conectați-l bara de căutare și tableView ieșiri cu bara de căutare și, respectiv, tabelul. Există câteva alte lucruri pe care trebuie să le facem înainte să terminăm cu tabloul de bord.

Deschide Biblioteca de obiecte și trageți un element de buton de bare în bara de navigare. Selectați elementul butonului bara, conectați-l cu Anulare: acțiunea pe care am declarat-o în interfața controlerului de vizualizare a căutării și o schimbăm Identificator în Atribuții Inspector la Anulare.


Glisați un element de buton de bare în bara de navigare a controlerului de vizualizare (nu în modulul de vizualizare a căutării) și schimbați-l Identificator în Atribuții Inspector la Adăuga. Trageți de la elementul butonului bară spre controlerul de navigare al controlerului de vizualizare a căutării și selectați modal din meniul care apare. Acest lucru creează o problemă de la controlerul de vizualizare la controlerul de navigare al controlerului de vizualizare a căutării.

Dacă ați controla trageți de la butonul de bare al controlerului de vizualizare direct la controlerul de vizualizare a căutării în locul controlerului de navigare, controlerul de navigație nu ar fi niciodată instanțiat și nu ați vedea o bară de navigare în partea superioară a controlerului de vizualizare a căutării.

Pasul 4: Implementarea tabelului

Înainte de a implementa UITableViewDataSource și UITableViewDelegate protocoale în MTSearchViewController , trebuie să declarăm o proprietate care stochează rezultatele căutării pe care le vom reveni din API-ul de căutare iTunes. Denumiți proprietatea podcast-uri așa cum se arată mai jos. De asemenea, declarăm un șir static care va servi drept identificator de reutilizare a celulelor. Aceasta corespunde identificatorului pe care l-am fixat pe celula prototip cu câteva momente în urmă.

 #import "MTSearchViewController.h" @interface MTSearchViewController () @property (puternic, nonatomic) NSMutableArray * podcasturi; @Sfârșit
 statică NSString * SearchCell = @ "SearchCell";

Implementarea sistemului numberOfSectionsInTableView: este la fel de ușor pe cât se întâmplă. Ne intoarcem 1 dacă self.podcasts nu este zero și 0 dacă este. Implementarea sistemului tableView: numberOfRowsInSection: este destul de asemănătoare, după cum puteți vedea mai jos. În tableView: cellForRowAtIndexPath:, cerem vizualizarea tabelului pentru o celulă prin trecerea identificatorului de reutilizare a celulelor, pe care l-am declarat mai devreme, și indexPath. Atragem elementul corespunzător din podcast-uri sursă de date și să actualizați celula de vizualizare a tabelului. Ambii tableView: canEditRowAtIndexPath: și tableView: canMoveRowAtIndexPath: întoarcere NU.

 - (NSInteger) numberOfSectionsInTableView: (UITableView *) tableView return self.podcasts? 1: 0; 
 - (NSInteger) tableView: (UITableView *) tableView numberOfRowsInSection: (NSInteger) sectiunea return self.podcasts? auto.podcasts.count: 0; 
 - (UITableViewCell *) tableView: (UITableView *) tableView cellForRowAtIndexPath: (NSIndexPath *) indexPath UITableViewCell * celula = [tableView dequeueReusableCellWithIdentifier: SearchCell forIndexPath: indexPath]; // Descărcați Podcast NSDictionary * podcast = [auto.podcasts objectAtIndex: indexPath.row]; // Configurați tabelul de vizualizare a celulei [cell.textLabel setText: [podcast objectForKey: @ "collectionName"]]; [cell.detailTextLabel setText: [podcast objectForKey: @ "artistName"]]; celule retur; 
 - (BOOL) tableView: (UITableView *) tableView canEditRowAtIndexPath: (NSIndexPath *) indexPath retur NO; 
 - (BOOL) tableView: (UITableView *) tableView canMoveRowAtIndexPath: (NSIndexPath *) indexPath return NO; 

Înainte de a rula aplicația, implementați aplicația Anulare: acțiune în care respingem controlerul de vizualizare a căutării.

 - (IBAction) anulați: (id) expeditor [self dismissViewControllerAnimated: YES finalizare: nil]; 

Construiți proiectul și rulați aplicația pentru a vă asigura că fundația funcționează conform așteptărilor. Este timpul să începeți să utilizați NSURLSession API pentru a interoga API-ul de căutare iTunes.

Pasul 5: Crearea unei sesiuni

Să începem prin a declara două proprietăți private suplimentare în MTSearchViewController clasă, sesiune și dataTask. sesiune variabila este folosită pentru a stoca o referință la NSURLSession instanța pe care o vom folosi pentru interogarea API-ului Apple. De asemenea, ținem o referință la sarcina de date pe care o vom folosi pentru solicitare. Acest lucru ne va permite să anulam sarcina de date dacă utilizatorul actualizează interogarea de căutare înainte de a primi un răspuns de la API. Dacă aveți un ochi pentru detalii, este posibil să fi observat că MTSearchViewController clasa este, de asemenea, conforme cu UIScrollViewDelegate protocol. Motivul pentru aceasta va deveni clar în câteva minute.

 #import "MTSearchViewController.h" @interface MTSearchViewController ()  @property (puternic, nonatomic) sesiune NSURLSession *; @property (puternic, nonatomic) NSURLSessionDataTask * dataTask; @property (puternic, nonatomic) NSMutableArray * podcast-uri; @Sfârșit

Sesiunea este creată în metoda getter, după cum puteți vedea mai jos. Implementarea sa nu ar trebui să aibă surprize dacă ați citit tutorialele anterioare. Depășim metoda getter din sesiune proprietatea de a încărca cu ușurință sesiunea și de a limita instanțiarea și configurația sesiunii în metoda getter. Acest lucru face ca un cod curat și elegant.

 - (NSURLSession *) sesiune if (! _Session) // Configurarea sesiunii inițializate NSURLSessionConfiguration * sessionConfiguration = [NSURLSessionConfiguration defaultSessionConfiguration]; // Configurați configurarea sesiunii [sessionConfiguration setHTTPAdditionalHeaders: @ @ "Accept": @ "application / json"]; // Initializați sesiunea _session = [NSURLSession sessionWithConfiguration: sessionConfiguration];  retur _session; 

Pasul 6: Căutarea

Pentru a răspunde la intrarea utilizatorului în bara de căutare, implementăm SearchBar: textDidChange: din UISearchBarDelegate protocol. Implementarea este simplă. Dacă searchText este zero, metoda se întoarce mai devreme. Dacă lungimea lui searchText are mai puțin de patru caractere, resetăm căutarea invocând resetSearch. Dacă interogarea are patru caractere sau mai mult, efectuăm o căutare prin apelare performSearch pe controlerul de vizualizare a căutării.

 - (void) searchBar: (UISearchBar *) căutareBar textDidChange: (NSString *) searchText if (! searchText) retur; dacă (searchText.length <= 3)  [self resetSearch];  else  [self performSearch];  

Înainte de a inspecta performSearch, Să aruncăm o privire rapidă resetSearch. Tot ce facem resetSearch clarifică conținutul podcast-uri și reîncărcarea vizualizării tabelului.

 - (void) resetSearch // Actualizare sursă de date [self.podcasts removeAllObjects]; // Actualizați tabelul [self.tableView reloadData]; 

Ridicarea greu se face în performSearch. După stocarea intrării utilizatorului într-o variabilă numită întrebare, verificăm dacă dataTask este setat. Dacă este setat, sunăm Anulare pe el. Acest lucru este important deoarece nu vrem să primim un răspuns de la un vechi solicitare care nu mai poate fi relevantă pentru utilizator. Acesta este și motivul pentru care avem o singură sarcină activă de date la un moment dat. Nu există niciun avantaj în trimiterea mai multor solicitări către API.

Apoi, solicităm sesiunii o nouă instanță de sarcini de date prin trecerea acesteia NSURL instanță și un handler de completare. Amintiți-vă că sesiunea este fabrica care creează sarcini. Niciodată nu ar trebui să creați sarcini. Dacă primim o sarcină validă de date din sesiune, sunăm relua așa cum am văzut în tutorialele anterioare.

Logica din cadrul procesorului de terminare este interesantă să spunem cel puțin. eroare obiect este important pentru noi din mai multe motive. Nu numai că ne va spune dacă s-a întâmplat ceva cu cererea, dar este, de asemenea, util pentru a determina dacă sarcina de date a fost anulată. Dacă obținem un obiect de eroare, verificăm dacă codul său de eroare este egal cu -999. Acest cod de eroare indică faptul că sarcina de date a fost anulată. Dacă primim un alt cod de eroare, vom înregistra eroarea în consolă. Într-o aplicație reală, va trebui să îmbunătățiți modul de gestionare a erorilor și să anunțați utilizatorul atunci când apare o eroare.

Dacă nu a fost transmisă nici o eroare handlerului de finalizare, vom crea un dicționar din NSData instanță care a fost transmisă muncitorului de finalizare și extragem rezultatele din acesta. Dacă avem o mulțime de rezultate cu care să lucrăm, noi le transmitem processResults:. Ai observat că am invocat-o processResults: într-un bloc GCD (Grand Central Dispatch)? De ce am făcut asta? Sper că vă aduceți aminte, pentru că este un detaliu foarte important. Nu avem nici o garantie ca handlerul de completare este invocat pe firul principal. Deoarece trebuie să actualizăm vizualizarea tabelului cu privire la firul principal, trebuie să ne asigurăm că aceasta processResults: este chemat pe firul principal.

 - (void) performSearch NSString * query = auto.searchBar.text; dacă (self.dataTask) [auto.dataTask anulați];  auto.dataTask = [auto.session dataTaskWithURL: [auto urlForQuery: interogare] completionHandler: ^ (NSData * date, NSURLResponse * răspuns, eroare NSError *) if (error.code! NSLog (@ "% @", eroare);  altceva NSDictionary * result = [NSJSONSerializare JSONObjectWithData: opțiuni de date: 0 eroare: zero]; NSArray * rezultate = [rezultatul obiectForKey: @ "rezultate"]; dispatch_async (dispatch_get_main_queue (), ^ dacă (rezultate) [auto processResults: results];); ]; dacă (self.dataTask) [auto.dataTask resume]; 

Înainte de a ne uita la punerea în aplicare a processResults:, Vreau să vă arăt rapid ce se întâmplă urlForQuery:, metoda de ajutor pe care o folosim performSearch. În urlForQuery:, noi înlocuim orice spații cu + semnați pentru a vă asigura că API-ul de căutare iTunes este mulțumit de ceea ce îi trimitem. Apoi creăm un NSURL instanță și returnați-o.

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

În processResults:, podcast-uri variabilă este șters, populate cu conținutul rezultate, iar rezultatele sunt afișate în vizualizarea tabelului.

 - (void) processResults: (NSArray *) rezultate if (! self.podcasts) self.podcasts = [NSMutableArray array];  // Actualizare sursă de date [self.podcasts removeAllObjects]; [auto.podcasts addObjectsFromArray: rezultate]; // Actualizați tabelul [self.tableView reloadData]; 

Pasul 6: Selectarea unui podcast

Când utilizatorul fixează un rând în vizualizarea tabelului pentru a selecta un podcast, tableView: didSelectRowAtIndexPath: din UITableViewDelegate se invocă protocolul. Implementarea lui poate părea ciudată la început, așa că permiteți-mi să explic ce se întâmplă. Selectăm podcast-ul care corespunde cu selecția utilizatorului, stochează-l în baza de date implicită pentru utilizatori și refuză controlerul de vizualizare a căutării. Nu informăm pe nimeni despre asta? De ce vom face acest lucru vor deveni clare odată ce vom continua implementarea MTViewController clasă.

 - (void) tableView: (UITableView *) tableView didSelectRowAtIndexPath: (NSIndexPath *) indexPath [tableView deselectRowAtIndexPath: indexPath animat: YES]; // Descărcați Podcast NSDictionary * podcast = [auto.podcasts objectAtIndex: indexPath.row]; // Actualizați utilizatorii Defatuți NSUserDefaults * ud = [NSUserDefaults standardUserDefaults]; [ud setObject: podcast pentruKey: @ "MTPodcast"]; [sincroniza]; // Renunțați la controlul vizualizării [self dismissViewControllerAnimated: YES completion: nil]; 

Pasul 7: Sfaturi de finisare

Sunt două detalii despre care vreau să vorbesc înainte de a reveni la MTViewController clasă. Atunci când controlerul de vizualizare a căutării este prezentat utilizatorului, este clar că dorește să caute podcast-uri. Prin urmare, este bine să prezentați imediat tastatura. Facem asta înăuntru viewDidAppear: așa cum se arată mai jos.

 - (vid) viewDidAppear: (BOOL) animat [super viewDidAppear: animat]; // Afișați tastatura [self.searchBar becomeFirstResponder]; 

Tastatura trebuie să se ascundă în momentul în care utilizatorul începe să deruleze rezultatele căutării. Pentru a realiza acest lucru, implementăm scrollViewDidScroll: din UIScrollViewDelegate protocol. Acest lucru explică de ce MTSearchViewController este în conformitate cu UIScrollViewDelegate protocol. Arunca o privire la punerea în aplicare a scrollViewDidScroll: prezentat mai jos.

 - (void) scrollViewDidScroll: (UIScrollView *) scrollView dacă [[self.searchBar isFirstResponder]) [auto.searchBar resignFirstResponder]; 
UITableView clasa este o subclasă de UIScrollView, care este motivul pentru care funcționează abordarea de mai sus.

4. Întoarcere înapoi

După cum am văzut mai devreme, stocăm selecția utilizatorului în baza de date a aplicațiilor implicite. Trebuie să actualizăm MTViewController pentru a utiliza selecția utilizatorului în controlerul de vizualizare a căutării. În controlerul de vizualizare viewDidLoad , încărcăm podcastul din baza de date implicită pentru utilizatori și adăugăm controlerul de vizualizare ca observator al bazei de date implicite pentru utilizatorul pentru calea cheie MTPodcast astfel încât controlerul de vizualizare să fie notificat atunci când valoarea pentru MTPodcast schimbări.

 - (vid) viewDidLoad [super viewDidLoad]; // Încarcă Podcast [self loadPodcast]; // Add Observer [[NSUserDefaults standardUserDefaults] addObserver: self forKeyPath: @ Opțiuni "MTPodcast": NSKeyValueObservingOptionNew context: NULL]; 

Tot ce facem loadPodcast stochează valoarea pentru MTPodcast din baza de date implicită a utilizatorilor din controlerul de vizualizare podcast proprietate. Această valoare va fi zero dacă baza de date implicită pentru utilizator nu conține o înregistrare pentru MTPodcast. Controlerul de vizualizare se va ocupa gratios de aceasta pentru noi. Rețineți că, în Obiectiv-C, puteți trimite mesaje către zero fără ca toată iadul să se despartă. Acest lucru are dezavantajele sale, dar cu siguranță are avantajele sale.

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

Aceasta înseamnă, de asemenea, că trebuie să declarăm o proprietate numită podcast în fișierul de implementare a controlerului de vizualizare.

 #import "MTViewController.h" @interface MTViewController () @property (puternic, nonatomic) NSDictionary * podcast; @Sfârșit

Să aruncăm o privire rapidă setPodcast: și updateView.

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

Când valoarea din baza de date implicită a utilizatorului modifică cheia MTPodcast, controlerul de vizualizare poate răspunde la această modificare observeValueForKeyPath: ofObject: schimbare: Context:. Așa funcționează observarea valorii cheie. Tot ceea ce facem în această metodă este actualizarea valorii controlerului de vizualizare podcast proprietate.

 - (void) observeValueForKeyPath: (NSString *) cheiePath ofObject: (id) modificarea obiectului: (NSDictionary *) schimbare context: (void *) context if ([keyPath esteEqualToString: @ "MTPodcast"]) self.podcast = objectForKey: @ "MTPodcast"]; 

Când lucrați cu respectarea valorii cheie, este esențial să fiți conștienți de gestionarea memoriei și să păstrați ciclurile. În acest caz, înseamnă că trebuie să eliminăm controlerul de vizualizare ca observator când controlerul de vizualizare este dezalocat.

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

5. Preluarea și parsarea fluxului

Pasul 1: Adăugarea dependențelor

Răspunsul pe care îl primim din API-ul de căutare iTunes include a adresă url feed atribut pentru fiecare podcast. Am putea să preluăm manual feedul și să îl analizăm. Cu toate acestea, pentru a economisi ceva timp, vom folosi MWFeedParser, o bibliotecă populară care poate face acest lucru pentru noi. Puteți să descărcați manual și să includeți biblioteca în proiectul dvs., dar voi opta pentru Cocoapods. Prefer Cocoapods pentru gestionarea dependențelor în proiectele iOS și OS X. Puteți citi mai multe despre Cocoapods pe site-ul său sau pe Mobiletuts+.

Am de gând să presupun că bijuteria Cocoapods este instalată pe sistemul tău. Puteți găsi instrucțiuni detaliate în acest tutorial.

Închideți Xcode, navigați la rădăcina proiectului dvs. Xcode și creați un fișier numit Podfile. Deschideți acest fișier în editorul de text ales și adăugați următoarele trei linii de cod. În prima linie, specificăm platforma și ținta de implementare, care este iOS 7 în acest exemplu. Următoarele două linii specifică o dependență a proiectului nostru Xcode. Primul este MWFeedParser biblioteca și am inclus și popularul SVProgressHUD bibliotecă, care va veni la îndemână un pic mai târziu.

 platformă: ios, '7' pod 'MWFeedParser' pod 'SVProgressHUD'

Deschideți o fereastră Terminal, navigați la rădăcina proiectului dvs. Xcode și executați comanda pod instalare. Aceasta ar trebui să instaleze dependențele și să creeze un spațiu de lucru Xcode. Când Cocoapods este terminat, instalând dependențele proiectului, acesta vă spune să utilizați spațiul de lucru creat pentru dvs. Acest lucru este important, așa că nu ignorați acest sfat. În rădăcina proiectului dvs. Xcode, veți vedea că Cocoapods a creat într-adevăr un spațiu de lucru Xcode pentru dvs. Faceți dublu clic pe acest fișier și ar trebui să fiți gata să mergeți.


Pasul 2: Preluarea și parsarea fluxului

Deschideți fișierul de implementare al MTViewController class, adăugați o declarație de import pentru MWFeedParser și SVProgressHUD, și să declare două proprietăți, episoade și feedParser. Trebuie, de asemenea, să facem MTViewController în conformitate cu MWFeedParserDelegate protocol.

 #import "MTViewController.h" #import "MWFeedParser.h" #import "SVProgressHUD.h" @interface MTViewController ()  @property (puternic, nonatomic) NSDictionary * podcast; @property (puternice, nonatomice) NSMutableArray * episoade; @property (puternic, nonatomic) MWFeedParser * feedParser; @Sfârșit

Apoi, actualizăm setPodcast: invocând fetchAndParseFeed, o metodă de ajutor în care folosim MWFeedParser clasa pentru a prelua și analiza feed-ul podcast-ului.

 - (void) setPodcast: (NSDictionary *) podcast if (_podcast! = podcast) _podcast = podcast; // Actualizare Vizualizare [self updateView]; // Fetch și Parse Feed [self fetchAndParseFeed]; 

În fetchAndParseFeed, scapăm de curentul nostru MWFeedParser dacă avem unul și inițializăm o nouă instanță cu adresa URL a fluxului de podcast. Am setat feedParseType proprietate la ParseTypeFull și setați controlerul de vizualizare ca delegat al parserului feedului. Înainte de a prelua hrana, folosim SVProgressHUD pentru a arăta un utilizator de progres HUD.

 - (void) fetchAndParseFeed if (! self.podcast) retur; NSURL * url = [NSURL URLWithString: [auto.podcast objectForKey: @ "feedUrl"]]; dacă (! url) returnează; dacă (self.feedParser) [self.feedParser stopParsing]; [self.feedParser setDelegate: zero]; [auto setFeedParser: zero];  // Episoade clare dacă (episoade auto) [auto setEpisodes: nil];  // Initializeaza parserul feedului self.feedParser = [[MWFeedParser alloc] initWithFeedURL: url]; // Configurează parserul feedului [self.feedParser setFeedParseType: ParseTypeFull]; [self.feedParser setDelegate: self]; // Afișați progresul HUD [SVProgressHUD showWithMaskType: SVProgressHUDMaskTypeGradient]; // Începeți parsarea [self.feedParser parse]; 

Trebuie, de asemenea, să punem în aplicare două metode MWFeedParserDelegate protocol, feedParser: didParseFeedItem: și feedParserDidFinish:. În feedParser: didParseFeedItem:, inițializăm episoade dacă este necesar, și să îi transmiteți elementul de alimentare pe care analizatorul feed-ului ni-l deține.

 - (void) feedParser: (paragraful MWFeedParser *) didParseFeedItem: (MWFeedItem *) element if (! self.episodes) self.episodes = [NSMutableArray array];  [auto.episode addObject: element]; 

În feedParserDidFinish:, renunțăm la progresul HUD și actualizăm vizualizarea tabelului. Ai spus vizualizarea tabelului? Asta e corect. Trebuie să adăugăm o vizualizare de tabel și să implementăm cerințele necesare UITableViewDataSource metode de protocol.

 - (void) feedParserDidFinish: (paragraful MWFeedParser *) // Renunțarea la progresul HUD [respingerea SVProgressHUD]; // Actualizare Vizualizare [self.tableView reloadData]; 

Pasul 3: Afișarea fluxului

Înainte de a actualiza interfața cu utilizatorul, deschideți MTViewController.h, declarați o priză pentru vizualizarea tabelului și informați compilatorul despre MTViewController clasa este conformă cu UITableViewDataSource și UITableViewDelegate protocoale.

 #import  @ interfață MTViewController: UIViewController  @property (slab, nonatomic) IBOutlet UITableView * tableView; @Sfârșit

Deschideți încă o dată tabloul de bord principal și adăugați o vizualizare de tabel la vizualizarea controlerului de vizualizare. Conectați vizualizarea tabelului sursă de date și delega ieșiți împreună cu controlerul de vizualizare și conectați controlerul de vizualizare tableView ieșiți cu vizualizarea tabelului. Selectați vizualizarea tabelului, deschideți Atribuții Inspector, și setați numărul de celule prototip 1. Selectați celula prototip, setați stilul acesteia Subtitlu, și dați-i un identificator de EpisodeCell.


Înainte de a implementa UITableViewDataSource protocol, declarați un șir static numit EpisodeCell în MTViewController.m. Aceasta corespunde cu identificatorul stabilit pentru celula prototipului din storyboard.

 statică NSString * EpisodeCell = @ "EpisodeCell";

Implementarea sistemului UITableViewDataSource protocolul este simplu ca plăcintă și foarte similar cu modul în care am implementat protocolul în controlerul de vizualizare a căutării. Singura diferență este că episoade variabila conține instanțe ale MWFeedItem clasă în loc de NSDictionary instanțe.

 - (NSInteger) numberOfSectionsInTableView: (UITableView *) tableView return self.episodes? 1: 0; 
 - (NSInteger) tableView: (UITableView *) tableView numberOfRowsInSection: (NSInteger) sectiunea return self.episodes? auto.episodes.count: 0; 
 - (UITableViewCell *) tableView: (UITableView *) tableView cellForRowAtIndexPath: (NSIndexPath *) indexPath UITableViewCell * celula = [tableView dequeueReusableCellWithIdentifier: EpisodeCell forIndexPath: indexPath]; // Returnați elementul Feed MWFeedItem * feedItem = [auto.episodes objectAtIndex: indexPath.row]; // Configurează tabelul de vizualizare a celulei [cell.textLabel setText: feedItem.title]; [cell.detailTextLabel setText: [NSString șirWithFormat: @ "% @", feedItem.date]]; celule retur; 
 - (BOOL) tableView: (UITableView *) tableView canEditRowAtIndexPath: (NSIndexPath *) indexPath retur NO; 
 - (BOOL) tableView: (UITableView *) tableView canMoveRowAtIndexPath: (NSIndexPath *) indexPath return NO; 

Rulați aplicația în Simulatorul iOS sau pe un dispozitiv fizic și executați-o prin pașii săi. Acum ar trebui să puteți căuta podcast-uri, să selectați un podcast din listă și să vedeți episoadele sale.


Concluzie

Am făcut multe în acest tutorial, dar avem încă destul de mult de lucru în fața noastră. În tutorialul următor, mărim intensitatea descărcării episoadelor din feed și vom discuta descărcări de fundal sau în afara procesului. Rămâneți aproape.

Cod