Arbeta med NSURLSession Del 3

I de tidigare handledningarna undersökte vi grunden för NSURLSession API. Det finns en annan egenskap hos NSURLSession API som vi inte har tittat på ännu, det vill säga uppladdningar och nedladdningar utan process. I de följande två handledningarna kommer jag att visa dig hur man skapar en mycket enkel podcastklient som möjliggör bakgrunds nedladdningar.


Introduktion

Den podcastklient som vi ska skapa kommer inte att bli så funktionell. Det gör att användaren kan fråga i iTunes Search API för en lista med podcaster, välja en podcast och hämta episoder. Eftersom vi fokuserar på NSURLSession API, kommer vi inte att gå in på att spela de episoder som nedladdningen av programmet.

Projektet kommer emellertid att lära dig hur man använder datauppgifter och hämtar uppgifter i en verklig världsapplikation. Podcast-klienten möjliggör också bakgrundsdownloads som vi kommer att utnyttja NSURLSessionAPI: n utan processer. Vi har en hel del saker att göra så låt oss inte slösa tid och komma igång.


1. Projektinställningar

Släck upp Xcode 5, välj Nytt> Projekt ... från Fil menyn och välj Enkel visningsprogram mall från listan över iOS-programmallar. Namn på ansökan Singlecast, ställa in Enhetsfamilj till iPhone, och berätta för Xcode där du vill spara projektet. Träffa Skapa att skapa projektet.




2. Uppdatera Storyboard

Det första vi behöver göra är att redigera projektets huvudsakliga storyboard. Öppna Main.storyboard, välj storyboardens enda vykontroll och välj Bädda in> Navigation Controller från Redaktör meny. Anledningen till inbäddning av visningsstyrenheten i en navigeringsenhet kommer att bli tydlig senare i denna handledning.



3. Sök Visa Controller

Steg 1: Skapa klassfiler

Som jag nämnde i introduktionen, för att hålla saker enkelt, kommer användaren bara att kunna prenumerera på en podcast. Låt oss börja med att skapa sökvisningskontrollen. Välj Ny> Fil ... från Fil menyn och välj Mål-C-klass från alternativen till höger. Namnge klassen MTSearchViewController och gör det till en underklass av UIViewController. Lämna kryssrutan märkt Med XIB för användargränssnitt okontrollerat. Berätta Xcode där du vill spara klassfilerna och träffa Skapa.


Steg 2: Uppdatera klassgränssnittet

Innan vi skapar användargränssnittet öppnar du tittelkontrollens huvudfiler och uppdaterar klassens gränssnitt som visas nedan. Vi anger att MTSearchViewController klassen överensstämmer med UITableViewDataSource, UITableViewDelegate, och UISearchBarDelegate protokoll, vi förklarar två försäljningsställen, sökruta och Tableview liksom en åtgärd, annullera, att avvisa kontrollen för sökvyn.

 #importera  @interface MTSearchViewController: UIViewController  @property (svag, ickeatomisk) IBOutlet UISearchBar * searchBar; @property (svag, ickeatomisk) IBOutlet UITableView * tableView; - (IBAction) Avbryt: (id) avsändare; @slutet

Steg 3: Skapa användargränssnitt

Revisera projektets huvudsakliga storyboard och dra en ny vykontroll från Objektbibliotek till höger. Välj den nya vynkontrollen, öppna Identitetsinspektör till höger och ställ in kontrollenhetens klass till MTSearchViewController. Med den nya vynkontrollen som fortfarande valts, öppnar du Redaktör menyn och välj Bädda in> Navigation Controller. Dra en tabellvy till vyens kontroll och välj tabellvyn datakälla och delegera uttag med sökvisningskontrollenhet.


Med tabellvyn som fortfarande valts öppnar du Attribut Inspector, och ange antalet prototypceller till 1. Välj prototypcellen och ställ in dess stilegenskap till Texta och dess identifierare till SearchCell.


Dra en sökfält från Objektbibliotek och lägg till den i tabellvyens huvudvy. Välj sökfältet och anslut dess delegera uttag med bildkontrollen.


Välj vykontrollen och anslut den sökruta och Tableview uttag med respektive sökfält och tabellvy. Det finns några andra saker som vi behöver göra innan vi är färdiga med storyboardet.

Öppna Objektbibliotek och dra ett streckknappspost till navigeringsfältet. Välj knappknappsposten, anslut den till annullera: åtgärd som vi förklarade i sökvynskontrollens gränssnitt och ändra dess Identifierare i Attribut Inspector till Annullera.


Dra ett streckknappspost till navigeringsfältet i vykontrollen (inte sökkontrollen) och ändra dess Identifierare i Attribut Inspector till Lägg till. Styr dra från knappknappsposten till sökkontrollens navigationsstyrenhet och välj modal från menyn som dyker upp. Detta skapar en segue från visningsregulatorn till sökkontrollens navigationsstyrning.

Om du skulle styra dra från visningsregulatorens streckknappspost direkt till sökvisningsregulatorn i stället för dess navigationsstyrenhet, skulle navigeringskontrollen aldrig bli instantierad och du skulle inte se en navigeringsfält överst i sökvynskontrollen.

Steg 4: Implementering av tabellvyn

Innan vi implementerar UITableViewDataSource och UITableViewDelegate protokoll i MTSearchViewController klass måste vi deklarera en egenskap som lagrar sökresultaten vi kommer tillbaka från iTunes Search API. Namnge egendomen podcasts enligt nedanstående. Vi förklarar också en statisk sträng som ska fungera som en cellåtervinningsidentifierare. Det motsvarar den identifierare vi satt på prototypcellen för några minuter sedan.

 #import "MTSearchViewController.h" @interface MTSearchViewController () @property (stark, ickeatomisk) NSMutableArray * podcasts; @slutet
 statisk NSString * SearchCell = @ "SearchCell";

Genomförandet av numberOfSectionsInTableView: är lika enkelt som det blir. Vi återvänder 1 om self.podcasts är inte noll och 0 om det är. Genomförandet av Tableview: numberOfRowsInSection: är ganska lika som du kan se nedan. I Tableview: cellForRowAtIndexPath:, vi frågar tabellvyn för en cell genom att skicka återanvändningsidentifieraren, som vi förklarade tidigare och indexPath. Vi hämtar motsvarande föremål från podcasts datakälla och uppdatera tabellvyns cellen. Både Tableview: canEditRowAtIndexPath: och Tableview: canMoveRowAtIndexPath: lämna tillbaka NEJ.

 - (NSInteger) numberOfSectionsInTableView: (UITableView *) tableView return self.podcasts? 1: 0; 
 - (NSInteger) tableView: (UITableView *) tableView numberOfRowsInSection: (NSInteger) avsnitt return self.podcasts? self.podcasts.count: 0; 
 - (UITableViewCell *) tableView: (UITableView *) tableVisa cellForRowAtIndexPath: (NSIndexPath *) indexPath UITableViewCell * cell = [tableView dequeueReusableCellWithIdentifier: SearchCell forIndexPath: indexPath]; // Hämta podcast NSDictionary * podcast = [self.podcasts objectAtIndex: indexPath.row]; // Konfigurera tabellvycell [cell.textLabel setText: [podcast objectForKey: @ "collectionName"]]; [cell.detailTextLabel setText: [podcast objectForKey: @ "artistName"]]; returcell; 
 - (BOOL) tableView: (UITableView *) tableView canEditRowAtIndexPath: (NSIndexPath *) indexPath return NO; 
 - (BOOL) tableView: (UITableView *) tableView kanMoveRowAtIndexPath: (NSIndexPath *) indexPath return NO; 

Innan du kör programmet, implementera annullera: Åtgärd där vi avvisar sökvynskontrollen.

 - (IBAction) avbryta: (id) avsändare [self dismissViewControllerAnimated: YES completion: nil]; 

Bygg projektet och kör programmet för att se till att stiftelsen fungerar som förväntat. Det är dags att börja använda NSURLSession API för att fråga iTunes Search API.

Steg 5: Skapa en session

Låt oss börja med att deklarera ytterligare två privata fastigheter i MTSearchViewController klass, session och dataTask. De session variabel används för att lagra en referens till NSURLSession Exempel vi använder för att fråga Apples API. Vi hyser också en hänvisning till den datauppgift som vi ska använda för begäran. Detta gör det möjligt för oss att avbryta datauppgiften om användaren uppdaterar sökfrågan innan vi har fått ett svar från API: n. Om du har ett öga för detaljer kan du ha märkt att MTSearchViewController klassen överensstämmer också med UIScrollViewDelegate protokoll. Anledningen till detta kommer att bli tydligt om några minuter.

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

Sessionen skapas i sin getter-metod som du kan se nedan. Dess genomförande borde inte innebära några överraskningar om du har läst tidigare tutorials. Vi åsidosätter gettermetoden för session egenskapen att laddigt ladda sessionen och begränsa sessionens instantiering och konfiguration i sin getter-metod. Detta ger ren och elegant kod.

 - (NSURLSession *) session if (! _Session) // Initialisera sessionskonfiguration NSURLSessionConfiguration * sessionConfiguration = [NSURLSessionConfiguration defaultSessionConfiguration]; // Konfigurera sessionskonfiguration [sessionConfiguration setHTTPAdditionalHeaders: @ @ "Accept": @ "application / json"]; // Initiera sessionen _session = [NSURLSession sessionWithConfiguration: sessionConfiguration];  returnera _session; 

Steg 6: Söka

För att svara på användarens inmatning i sökfältet implementerar vi Searchbar: textDidChange: av UISearchBarDelegate protokoll. Implementeringen är enkel. Om searchText är noll, Metoden återvänder tidigt. Om längden på searchText är mindre än fyra tecken långt, återställer vi sökningen genom att åberopa resetSearch. Om frågan är fyra tecken eller längre, utför vi en sökning genom att ringa performSearch på sökvynskontrollen.

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

Innan vi inspekterar performSearch, låt oss ta en snabb titt på resetSearch. Allt vi gör i resetSearch rensar innehållet i podcasts och laddning av tabellvyn.

 - (void) resetSearch // Uppdatera datakälla [self.podcasts removeAllObjects]; // Uppdatera tabellvisning [self.tableView reloadData]; 

Den tunga lyftningen är klar i performSearch. Efter lagring av användarens inmatning i en variabel som heter fråga, vi kolla om dataTask är inställd. Om den är inställd ringer vi annullera på det. Detta är viktigt eftersom vi inte vill få svar från en gammal begäran som kanske inte längre är relevant för användaren. Detta är också anledningen till att vi bara har en aktiv datainställning vid en gång. Det finns ingen fördel att skicka flera förfrågningar till API: n.

Därefter frågar vi sessionen för en ny datauppgift instans genom att skicka den en NSURL instans och en färdighetshandlare. Kom ihåg att sessionen är den fabrik som skapar uppgifter. Du borde aldrig skapa uppgifter själv. Om vi ​​får en giltig datauppgift från sessionen, ringer vi återuppta på det som vi såg i de tidigare handledningarna.

Logiken inom färdigställaren är intressant minst sagt. De fel objekt är viktigt för oss av flera skäl. Det kommer inte bara att berätta om något gick fel med förfrågan, men det är också användbart för att avgöra om datauppgiften avbröts. Om vi ​​får ett felobjekt kontrollerar vi om dess felkod är lika med -999. Den här felkoden anger att datauppgiften har avbrutits. Om vi ​​får en annan felkod loggar vi felet till konsolen. I en riktig applikation behöver du förbättra felhanteringen och meddela användaren när ett fel kastas.

Om inget fel skickades till slutföringshanteraren skapar vi en ordlista från NSData instans som skickades till färdigställaren och vi extraherar resultaten från den. Om vi ​​har en rad resultat att arbeta med skickar vi den vidare till processResults:. Visste du att vi åberopade processResults: i ett GCD (Grand Central Dispatch) block? Varför gjorde vi det? Jag hoppas du kommer ihåg, för det är en mycket viktig detalj. Vi har ingen garanti för att färdigställningshanteraren är påkallad på huvudtråden. Eftersom vi behöver uppdatera tabellvyn på huvudgänget måste vi se till att processResults: kallas på huvudgängan.

 - (void) performSearch NSString * query = self.searchBar.text; om (self.dataTask) [self.dataTask Cancel];  self.dateTask = [self.session dataTaskWithURL: [self urlForQuery: query] completionHandler: ^ (NSData * data, NSURLResponse * svar, NSError * fel) if (error) if (error.code! = -999)  NSLog (@ "% @", fel);  annat NSDictionary * result = [NSJSONSerialization JSONObjectWithData: dataalternativ: 0 error: nil]; NSArray * results = [result objectForKey: @ "results"]; dispatch_async (dispatch_get_main_queue (), ^ if (resultat) [självprocessResultat: resultat];); ]; om (self.dataTask) [self.dataTask återupptas]; 

Innan vi tittar på genomförandet av processResults:, Jag vill snabbt visa dig vad som händer i urlForQuery:, hjälparmetoden vi använder i performSearch. I urlForQuery:, Vi ersätter alla mellanslag med a + logga in för att se till att iTunes Search API är nöjd med det vi skickar det till. Vi skapar då en NSURL instämma med det och returnera det.

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

I processResults:, de podcasts variabel rensas, befolkade med innehållet i resultat, och resultaten visas i tabellvyn.

 - (void) processResults: (NSArray *) resultat if (! self.podcasts) self.podcasts = [NSMutableArray array];  // Uppdatera datakälla [self.podcasts removeAllObjects]; [self.podcasts addObjectsFromArray: results]; // Uppdatera tabellvisning [self.tableView reloadData]; 

Steg 6: Välja en podcast

När användaren drar en rad i tabellvyn för att välja en podcast, Tableview: didSelectRowAtIndexPath: av UITableViewDelegate protokollet åberopas. Dess genomförande kan tyckas udda i början så låt mig förklara vad som händer. Vi väljer poddsändningen som motsvarar användarens val, lagrar den i programmets användarinställningsdatabas och avvisar sökvisningskontrollen. Vi meddelar inte någon om detta? Varför vi gör det kommer att bli tydliga när vi fortsätter att implementera MTViewController klass.

 - (void) tableView: (UITableView *) tableView didSelectRowAtIndexPath: (NSIndexPath *) indexPath [tableView deselectRowAtIndexPath: indexPath animated: YES]; // Hämta podcast NSDictionary * podcast = [self.podcasts objectAtIndex: indexPath.row]; // Uppdatera användarens defatuler NSUserDefaults * ud = [NSUserDefaults standardUserDefaults]; [ut setObject: podcast forKey: @ "MTPodcast"]; [ut synkronisera]; // Avvisa View Controller [self dismissViewControllerAnimated: YES completion: nil]; 

Steg 7: Efterbehandling

Det finns två detaljer jag vill prata om innan jag återvänder till MTViewController klass. När sökvynkontrollen presenteras för användaren är det tydligt att hon vill söka efter podcaster. Det är därför en bra idé att omedelbart presentera tangentbordet. Vi gör det här viewDidAppear: enligt nedanstående.

 - (void) viewDidAppear: (BOOL) animerad [super viewDidAppear: animated]; // Visa tangentbord [self.searchBar becomeFirstResponder]; 

Tangentbordet måste dölja det ögonblick som användaren börjar bläddra igenom sökresultaten. För att uppnå detta genomför vi scrollViewDidScroll: av UIScrollViewDelegate protokoll. Detta förklarar varför MTSearchViewController överensstämmer med UIScrollViewDelegate protokoll. Ta en titt på genomförandet av scrollViewDidScroll: visas nedan.

 - (void) scrollViewDidScroll: (UIScrollView *) scrollView if ([self.searchBar isFirstResponder]) [self.searchBar resignFirstResponder]; 
De UITableView klassen är en underklass av UIScrollView, vilket är anledningen till att ovanstående synsätt fungerar.

4. Looping Back

Som vi såg tidigare lagrar vi användarens val i programmets standardinställningar. Vi behöver uppdatera MTViewController klass för att använda användarens val i sökvynskontrollen. I visningsregulatorens viewDidLoad metod laddar vi podcasten från databasen för användarens standard och vi lägger till visningsstyrenheten som observatör av användarens standarddatabas för nyckelvägen MTPodcast så att visningskontrollen meddelas när värdet för MTPodcast förändringar.

 - (void) viewDidLoad [super viewDidLoad]; // Ladda Podcast [self loadPodcast]; // Lägg till Observer [[NSUserDefaults standardUserDefaults] addObserver: self forKeyPath: @ "MTPodcast" alternativ: NSKeyValueObservingOptionNew context: NULL]; 

Allt vi gör i loadPodcast lagrar värdet för MTPodcast från databasen för användarinställningar i vykontrollen podcast fast egendom. Detta värde kommer att vara noll Om användarens standarddatabas inte innehåller en post för MTPodcast. Utsiktskontrollen hanterar detta elegant för oss. Kom ihåg att i Mål-C kan du skicka meddelanden till noll utan att helvetet släpper loss. Detta har sina nackdelar, men det har säkert dess fördelar med.

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

Detta innebär också att vi måste deklarera en egendom som heter podcast i visningskontrollens implementeringsfil.

 #import "MTViewController.h" @interface MTViewController () @property (stark, ickeatomisk) NSDictionary * podcast; @slutet

Låt oss också ta en snabb titt på setPodcast: och updateView.

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

När värdet i användarens standarddatabas ändras för nyckeln MTPodcast, Visningsansvarig kan svara på denna ändring i observeValueForKeyPath: ofObject: change: sammanhang:. Det är så hur viktiga värden observerar fungerar. Allt vi gör i den här metoden uppdaterar värdet på vykontrollen podcast fast egendom.

 - (void) observeValueForKeyPath: (NSString *) keyPath ofObject: (id) objektbyte: (NSDictionary *) ändra kontext: (void *) sammanhang if ([keyPath isEqualToString: @ "MTPodcast"]) self.podcast = objectForKey: @ "MTPodcast"]; 

När man arbetar med viktiga värden observerar, är det instrumental att vara medveten om minneshantering och behåll cykler. I det här fallet betyder det att vi måste ta bort bildkontrollen som observatör när visningsregulatorn är avdelad.

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

5. Hämta och analysera flödet

Steg 1: Lägga till beroende

Svaret som vi kommer tillbaka från iTunes Search API innehåller en feedUrl attribut för varje podcast. Vi kunde manuellt hämta matningen och analysera den. Men för att spara lite tid använder vi MWFeedParser, ett populärt bibliotek som kan göra det för oss. Du kan manuellt ladda ner och inkludera biblioteket i ditt projekt, men jag ska välja Cocoapods. Jag föredrar Cocoapods för hantering av beroenden i IOS och OS X-projekt. Du kan läsa mer om Cocoapods på sin hemsida eller på Mobiletuts+.

Jag kommer att anta att Cocoapods pärla är installerad på ditt system. Du kan hitta detaljerade instruktioner i denna handledning.

Avsluta Xcode, navigera till roten till ditt Xcode-projekt och skapa en fil med namnet Podfile. Öppna den här filen i din textredigerare och välj följande tre rader kod. I första raden specificerar vi plattformen och implementeringsmålet, vilket är iOS 7 i det här exemplet. De två följande raderna anger var och en ett beroende av vårt Xcode-projekt. Den första är MWFeedParser bibliotek och jag har också inkluderat den populära SVProgressHUD bibliotek, vilket kommer att vara till nytta lite senare.

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

Öppna ett terminalfönster, navigera till roten i ditt Xcode-projekt och kör kommandot pod installera. Detta bör installera beroenden och skapa en Xcode-arbetsyta. När Cocoapods är färdig med att installera projektets beroenden berättar det dig att använda den arbetsyta som den skapade för dig. Detta är viktigt så ignorera inte detta råd. I roten till ditt Xcode-projekt ser du att Cocoapods verkligen skapat en Xcode-arbetsyta för dig. Dubbelklicka på den här filen och du bör vara redo att gå.


Steg 2: Hämta och analysera flödet

Öppna implementeringsfilen för MTViewController klass, lägg till ett import uttalande för MWFeedParser och SVProgressHUD, och deklarera två egenskaper, episoder och feedParser. Vi måste också göra MTViewController överensstämma med MWFeedParserDelegate protokoll.

 #import "MTViewController.h" #import "MWFeedParser.h" #import "SVProgressHUD.h" @interface MTViewController ()  @property (stark, icke-atomisk) NSDictionary * podcast; @property (strong, nonatomic) NSMutableArray * episoder; @property (stark, ickeatomisk) MWFeedParser * feedParser; @slutet

Därefter uppdaterar vi setPodcast: genom att åberopa fetchAndParseFeed, en hjälparmetod där vi använder MWFeedParser klass för att hämta och analysera podcastens matning.

 - (void) setPodcast: (NSDictionary *) podcast if (_podcast! = podcast) _podcast = podcast; // Uppdatera Visa [self updateView]; // Hämta och analysera flöde [självhämtningAndParseFeed]; 

I fetchAndParseFeed, vi blir av med vår nuvarande MWFeedParser exempel om vi har en och initierar en ny instans med podcastens matningsadress. Vi ställer in feedParseType egendom till ParseTypeFull och ställa in visningskontrollen som flödesparsers delegat. Innan vi hämtar matningen använder vi SVProgressHUD för att visa framsteg HUD för användaren.

 - (void) fetchAndParseFeed if (! self.podcast) returnera; NSURL * url = [NSURL URLWithString: [self.podcast objectForKey: @ "feedUrl"]]; om (! url) återvänder; om (self.feedParser) [self.feedParser stopParsing]; [self.feedParser setDelegate: nil]; [self setFeedParser: nil];  // Rensa episoder om (self.episodes) [self setEpisodes: nil];  // Initiera FeedParser self.feedParser = [[MWFeedParser-allokering] initWithFeedURL: url]; // Konfigurera flödesparser [self.feedParser setFeedParseType: ParseTypeFull]; [self.feedParser setDelegate: self]; // Visa framsteg HUD [SVProgressHUD showWithMaskType: SVProgressHUDMaskTypeGradient]; // Starta Parsing [self.feedParser parse]; 

Vi måste också genomföra två metoder för MWFeedParserDelegate protokoll, feedParser: didParseFeedItem: och feedParserDidFinish:. I feedParser: didParseFeedItem:, vi initierar episoder egendom om det behövs och skicka det matningsposten som matningsparsaren händer till oss.

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

I feedParserDidFinish:, Vi avvisar framstegen HUD och uppdaterar tabellvyn. Sade du bordsbild? Det är rätt. Vi måste lägga till en tabellvy och genomföra nödvändiga UITableViewDataSource protokollmetoder.

 - (void) feedParserDidFinish: (MWFeedParser *) parser // Avvisa framsteg HUD [SVProgressHUD dismiss]; // Uppdatera Visa [self.tableView reloadData]; 

Steg 3: Visar flödet

Innan vi uppdaterar användargränssnittet öppnar du MTViewController.h, Förklara ett uttag för tabellvyn och berätta för kompilatorn MTViewController klassen överensstämmer med UITableViewDataSource och UITableViewDelegate protokoll.

 #importera  @interface MTViewController: UIViewController  @property (svag, ickeatomisk) IBOutlet UITableView * tableView; @slutet

Öppna huvud storyboard en gång till och lägg till en tabellvy till vystyrningens vy. Anslut tabellvyn datakälla och delegera uttag med bildkontrollen och anslut bildkontrollen Tableview utlopp med tabellvyn. Välj tabellvyn, öppna Attribut Inspector, och ange antalet prototypceller till 1. Välj prototypcellen, sätt dess stil till Texta, och ge den en identifierare av EpisodeCell.


Innan vi implementerar UITableViewDataSource protokoll, förklara en statisk sträng som heter EpisodeCell i MTViewController.m. Detta motsvarar den identifierare vi ställde för prototypcellen i storyboardet.

 statisk NSString * EpisodeCell = @ "EpisodeCell";

Genomförande av UITableViewDataSource protokollet är enkelt som paj och mycket liknar hur vi implementerade protokollet i sökvisningskontrollen. Den enda skillnaden är att episoder variabel innehåller instanser av MWFeedItem klass i stället för NSDictionary instanser.

 - (NSInteger) numberOfSectionsInTableView: (UITableView *) tableView return self.episodes? 1: 0; 
 - (NSInteger) tableView: (UITableView *) tableView numberOfRowsInSection: (NSInteger) avsnitt return self.episodes? self.episodes.count: 0; 
 - (UITableViewCell *) tableView: (UITableView *) tableVisa cellForRowAtIndexPath: (NSIndexPath *) indexPath UITableViewCell * cell = [tableView dequeueReusableCellWithIdentifier: EpisodeCell forIndexPath: indexPath]; // Hämta matningsartikel MWFeedItem * feedItem = [self.episodes objectAtIndex: indexPath.row]; // Konfigurera tabellvycell [cell.textLabel setText: feedItem.title]; [cell.detailTextLabel setText: [NSString stringWithFormat: @ "% @", feedItem.date]]; returcell; 
 - (BOOL) tableView: (UITableView *) tableView canEditRowAtIndexPath: (NSIndexPath *) indexPath return NO; 
 - (BOOL) tableView: (UITableView *) tableView kanMoveRowAtIndexPath: (NSIndexPath *) indexPath return NO; 

Kör programmet i iOS-simulatorn eller på en fysisk enhet och kör den genom sina steg. Du ska nu kunna söka efter podcaster, välja en podcast från listan och se dess episoder.


Slutsats

Vi har gjort mycket i denna handledning, men vi har fortfarande en hel del arbete framför oss. I nästa handledning zoomar vi in ​​när du hämtar episoder från flödet och vi diskuterar nedladdningar i bakgrunden eller utan process. Håll dig igång.