Nätverk med NSURLSession Del 1

Ur ett utvecklingsperspektiv är en av de viktigaste förändringarna i iOS 7 och OS X Mavericks för det saken introduktionen av NSURLSession. Även om NSURLSession Det kan tyckas skrämmande vid första anblicken, det är viktigt att du förstår vad det är, hur det rör sig om NSURLConnection, och vad skillnaderna är. I denna serie tar jag dig igenom grunden för NSURLSession så du kan utnyttja denna nya teknik i dina egna applikationer.


Varför ersätt NSURLConnection?

Den första frågan du kanske frågar dig själv är varför Apple fann det nödvändigt att presentera NSURLSession medan vi är helt nöjda med NSURLConnection. Den verkliga frågan är om du är nöjd med NSURLConnection. Kommer du ihåg den tiden du förbannade och kastade saker på NSURLConnection? De flesta kakaoutvecklare har varit på den platsen, varför Apple bestämde sig för att gå tillbaka till ritbordet och skapa en mer elegant lösning som passar bättre för det moderna webben.

Även om NSURLSession och NSURLConnection har mycket gemensamt när det gäller hur de fungerar, på en grundläggande nivå är de helt annorlunda. Apple skapade NSURLSession att likna de allmänna begreppen i NSURLConnection, men du kommer att lära dig under denna serie att NSURLSession är modern, lättare att använda, och byggd med mobil i åtanke.


Vad är NSURLSession?

Innan jag diskuterar skillnaderna mellan NSURLSession och NSURLConnection, Det är en bra idé att först titta närmare på vad NSURLSession är. Trots sitt namn, NSURLSession Det är inte bara en annan klass du kan använda i en iOS- eller OS X-applikation. NSURLSession är först och främst en teknik precis som NSURLConnection är.

Sessioner är behållare

NSURLSession och NSURLConnection båda tillhandahåller ett API för att interagera med olika protokoll, t.ex. HTTP och HTTPS. Sessionsobjektet, en förekomst av NSURLSession klass, hanterar denna interaktion. Det är en mycket konfigurerbar behållare med ett elegant API som möjliggör finkorrigerad kontroll. Det erbjuder funktioner som saknas i NSURLConnection. Vad mer med NSURLSession, du kan utföra uppgifter som helt enkelt inte är möjliga med NSURLConnection, som att genomföra privat surfning.

uppgifter

Den grundläggande arbetsenheten när du arbetar med NSURLSession är uppgiften, en förekomst av NSURLSessionTask. Det finns tre typer av uppgifter, data uppgifter, ladda upp uppgifter, och ladda ner uppgifter.

  • Du använder oftast datauppgifter, vilka är instanser av NSURLSessionDataTask. Datauppgifter används för att begära data från en server, till exempel JSON-data. Den viktigaste skillnaden med uppladdning och nedladdning är att de returnerar data direkt till din ansökan istället för att gå igenom filsystemet. Data lagras endast i minnet.
  • Som namnet antyder används uppladdningsuppgifter för att ladda upp data till en avlägsen destination. De NSURLSessionUploadTask är en underklass av NSURLSessionDataTask och beter sig på ett liknande sätt. En av de viktigaste skillnaderna med en vanlig datauppgift är att uppladdningsuppgifter kan användas i en session skapad med en bakgrundssessionskonfiguration.
  • Hämta uppgifter, instanser av NSURLSessionDownloadTask, ärva direkt från NSURLSessionTask. Den viktigaste skillnaden med datafunktioner är att en nedladdningsuppgift skriver sitt svar direkt till en temporär fil. Det här skiljer sig ganska från en vanlig datauppgift som lagrar svaret i minnet. Är det möjligt att annullera en nedladdning uppgift och återuppta det vid en senare tidpunkt.

Som du kan föreställa dig är asynkronicitet ett nyckelbegrepp i NSURLSession. De NSURLSession API returnerar data genom att påkalla en slutförandebehandlare eller genom sessionens delegat. API av NSURLSession designades med flexibilitet i åtanke eftersom du kommer att märka lite senare i denna handledning.

Möt familjen

Som jag nämnde tidigare, NSURLSession är både en teknik och en klass som du ska arbeta med. De NSURLSession API innehåller ett antal klasser, men NSURLSession är den viktigaste komponenten som skickar förfrågningar och mottagande av svar. Konfigurationen av sessionsobjektet hanteras emellertid av en instans av NSURLSessionConfiguration klass. De NSURLSessionTask klassen och dess tre konkreta underklasser är arbetarna och används alltid i samband med en session, eftersom det är den session som skapar uppgiftsobjekten.

Delegation

Både NSURLSession och NSURLConnection lita starkt på delegationsmönstret. De NSURLSessionDelegate protokollet förklarar en handfull delegerade metoder för att hantera händelser på sessionen. Dessutom har NSURLSessionTask klass och underklasser vart och ett förklarar ett delegatprotokoll för hantering av händelser på uppgiftsnivå.

Gamla vänner

De NSURLSession API bygger på klasser som du redan är bekant med, till exempel NSURL, NSURLRequest, och NSURLResponse.


Vad är skillnaderna?

Hur gör det? NSURLSession avvika från NSURLConnection? Detta är en viktig fråga, för NSURLConnection avlägsnas inte av Apple. Du kan fortfarande använda NSURLConnection i dina projekt. Varför ska du använda NSURLSession?

Det första att förstå är att NSURLSession Exempel är det objekt som hanterar begäran och svaret. Detta liknar hur NSURLConnection fungerar, men nyckelfaktorn är att konfigurationen av förfrågan hanteras av sessionsobjektet, vilket är ett långlivat objekt. Detta görs genom NSURLSessionConfiguration klass. Det ger inte bara den NSURLSession API finkorrigerad konfiguration via NSURLSessionConfiguration klass uppmuntrar det åtskillnad av data (begäran om organ) från metadata. De NSURLSessionDownloadTask illustrerar detta bra genom att direkt skriva svaret på filsystemet.

Autentisering är enklare och hanteras mer elegant NSURLSession. De NSURLSession API hanterar autentisering på en anslutningsbasis istället för på begäran, till exempel NSURLConnection gör. De NSURLSession API gör det också bekvämare att tillhandahålla HTTP-alternativ och varje session kan ha en separat förvaringsbehållare beroende på hur du konfigurerar sessionen.

I introduktionen berättade jag det för dig NSURLSession ger ett modernt gränssnitt, vilket integrerar graciöst med iOS 7. Ett exempel på denna integration är NSURLSessions out-of-process uppladdningar och nedladdningar. NSURLSession är optimerad för att bevara batteriets livslängd, stöder paus, avbrytande och återupptagande av uppgifter samt UIKits multitasking API. Vad är inte att älska om NSURLSession?


Få dina fötter våta

Steg 1: Projektinställningar

Ett nytt API lär sig bäst av övning så det är dags att skjuta upp Xcode och få våra fötter blöt. Starta Xcode 5, skapa ett nytt projekt genom att välja Nytt> Projekt ... från Fil menyn och välj Enkel visningsprogram mall från listan över iOS-programmallar.


Ge ditt projekt ett namn, berätta Xcode där du vill spara det och klicka Skapa. Det finns inget behov av att sätta projektet under källkontroll.


Steg 2: Skapa ett sessionobjekt

När du arbetar med NSURLSession, Det är viktigt att förstå att sessionsobjektet, en förekomst av NSURLSession, är stjärnspelaren. Det hanterar förfrågningarna och svaren, konfigurerar förfrågningarna, hanterar sessionens lagring och tillstånd, etc. Att skapa en session kan göras på flera sätt. Det snabbaste sättet att komma igång är att använda NSURLSession's sharedSession klassmetod som visas nedan.

 - (void) viewDidLoad [super viewDidLoad]; NSURLSession * session = [NSURLSession sharedSession]; 

Skapa en session objekt i visningsregulatorens viewDidLoad metod som visas ovan. De session objekt vi skapade är bra för vårt exempel, men du vill ha lite mer flexibilitet i de flesta fall. De session objekt som vi just skapat använder det globala NSURLCache, NSHTTPCookieStorage, och NSURLCredentialStorage. Det betyder att det fungerar ungefär som en standard implementering av NSURLConnection.

Steg 3: Skapa en datauppgift

Att sätta session objekt att använda, låt oss fråga iTunes Store Search API och söka efter programvara som tillverkats av Apple. ITunes Store Search API är lätt att använda och kräver ingen autentisering, vilket gör den idealisk för vårt exempel.

För att fråga sök API måste vi skicka en förfrågan till https://itunes.apple.com/search och skicka några parametrar. Som vi såg tidigare, när vi använde NSURLSession API, en förfrågan representeras av en uppgift. För att söka sök API måste allt vi behöver är en datauppgift, en förekomst av NSURLSessionDataTask klass. Ta en titt på den uppdaterade viewDidLoad genomförandet visas nedan.

 - (void) viewDidLoad [super viewDidLoad]; NSURLSession * session = [NSURLSession sharedSession]; NSURLSessionDataTask * dataTask = [session dataTaskWithURL: [NSURL URLWithString: @ "https://itunes.apple.com/search?term=apple&media=software"] completionHandler: ^ (NSData * data, NSURLResponse * svar, NSError * fel)  NSDictionary * json = [NSJSONSerialization JSONObjectWithData: dataalternativ: 0 error: nil]; NSLog (@ "% @", json); ]; 

Det finns ett antal metoder tillgängliga för att skapa en uppgift, men det centrala begreppet att förstå är att session objekt gör själva uppbyggnaden och konfigurationen av uppgiften. I detta exempel åberopar vi dataTaskWithURL: completionHandler: och skicka det till en förekomst av NSURL såväl som en färdighetshandlare. Kompletteringshanteraren accepterar tre argument, den råa uppgifter om svaret (NSData), den svarobjekt (NSURLResponse), och en felobjekt (NSError). Om begäran är framgångsrik är felobjektet noll. Eftersom vi vet att förfrågan returnerar ett JSON-svar skapar vi en fundament objekt från data objekt som vi har fått och loggar utmatningen till konsolen.

Det är viktigt att förstå att fel objekt som skickas till färdigställningshanteraren är bara befolket, inte noll, om förfrågan misslyckades eller det uppstod ett fel. Med andra ord, om förfrågan returnerade a 404 svaret lyckades förfrågan vad gäller sessionerna. De fel objektet kommer då att vara noll. Detta är ett viktigt begrepp att förstå när man arbetar med NSURLSession och NSURLConnection för den sakens skull.

Bygg projektet och kör programmet i iOS-simulatorn eller på en fysisk enhet och inspekter Xcode's Console. Ingenting skrivs ut till konsolen. Vad gick fel? Som jag nämnde tidigare, NSURLSession API stöder pausar, avbryter och återupptar uppgifter eller förfrågningar. Detta beteende liknar det för NSOperation och det kan påminna dig om AFNetworking-biblioteket. En uppgift har a stat egenskap som anger om uppgiften är löpning (NSURLSessionTaskStateRunning), suspenderad (NSURLSessionTaskStateSuspended), avbrytande (NSURLSessionTaskStateCanceling), eller avslutad (NSURLSessionTaskStateCompleted). När ett sessionsobjekt skapar en uppgift startar uppgiften sitt liv i suspenderad stat. För att starta uppgiften måste vi berätta för det återuppta genom att ringa återuppta på uppgiften. Uppdatera viewDidLoad metod som visas nedan, kör programmet en gång till och inspektera utmatningen i konsolen. Uppdrag slutfört.

 - (void) viewDidLoad [super viewDidLoad]; NSURLSession * session = [NSURLSession sharedSession]; NSURLSessionDataTask * dataTask = [session dataTaskWithURL: [NSURL URLWithString: @ "https://itunes.apple.com/search?term=apple&media=software"] completionHandler: ^ (NSData * data, NSURLResponse * svar, NSError * fel)  NSDictionary * json = [NSJSONSerialization JSONObjectWithData: dataalternativ: 0 error: nil]; NSLog (@ "% @", json); ]; [dataTask resume]; 

Hämtar en fjärrresurs

I det föregående exemplet använde vi en slutföringshanterare för att behandla svaret vi mottog från förfrågan. Det är också möjligt att uppnå samma resultat genom att genomföra uppdragsdelegeringsprotokollen. Låt oss se vad som krävs för att ladda ner en bild genom att använda NSURLSession och den NSURLSessionDownloadTask.

Steg 1: Skapa användargränssnittet

Öppna MTViewController.h och skapa två uttag som visas nedan. Vi använder det första uttaget, en förekomst av UIImageView, för att visa den nedladdade bilden till användaren. Det andra utloppet, en förekomst av UIProgressView, kommer att visa framstegen i hämtningsuppgiften.

 #importera  @interface MTViewController: UIViewController @property (svag, ickeatomisk) IBOutlet UIImageView * imageView; @property (svag, ickeatomisk) IBOutlet UIProgressView * progressView; @slutet

Öppna projektets huvudsakliga storyboard (Main.storyboard), dra a UIImageView instämma i bildskärmens kontroll och koppla bildskärmskontrollens uttag som vi just skapat i huvudkontrollens huvudfiler. Upprepa denna process för framstegsvyn.


Steg 2: Skapa en nedladdningssats

I det här exemplet kommer vi inte att utnyttja sharedSession klassmetoden, eftersom vi behöver konfigurera session objekt som vi ska använda för att göra förfrågan. Uppdatera genomförandet av viewDidLoad enligt nedanstående.

 - (void) viewDidLoad [super viewDidLoad]; NSURLSessionConfiguration * sessionConfiguration = [NSURLSessionConfiguration defaultSessionConfiguration]; NSURLSession * session = [NSURLSession sessionWithConfiguration: sessionConfiguration delegate: self delegateQueue: nil]; NSURLSessionDownloadTask * downloadTask = [session downloadTaskWithURL: [NSURL URLWithString: @ "http://cdn.tutsplus.com/mobile/uploads/2013/12/sample.jpg"]]; [downloadTask resume]; 

För att förhindra att en kompilatorvarning dyker upp, se till att du överensstämmer med MTViewController klass till NSURLSessionDelegate och NSURLSessionDownloadDelegate protokoll som visas nedan.

 #import "MTViewController.h" @interface MTViewController ()  @slutet

I viewDidLoad, vi skapar en förekomst av NSURLSessionConfiguration klass genom att åberopa defaultSessionConfiguration klassmetod. Som anges i dokumentationen, uppträder sessionen med hjälp av standard sessionskonfigurationen som en förekomst av NSURLConnection i sin standardkonfiguration, vilket är bra för vårt exempel.

I det här exemplet skapar vi en NSURLSession exempel genom att åberopa sessionWithConfiguration: delegat: delegateQueue: klassmetod och passera sessionConfiguration objekt vi skapade för en stund sedan. Vi ställde upp kontrollen som session delegat och passerar noll som det tredje argumentet. Du kan ignorera det tredje argumentet för nu. Huvudskillnaden med föregående exempel är att vi ställer in sessions delegerad till vaktkontrollen.

För att ladda ner bilden måste vi skapa en nedladdningsuppgift. Vi gör detta genom att ringa downloadTaskWithURL:session objekt, passerar en instans av NSURL, och ringer återuppta på hämtningsuppgiften. Vi kunde ha använt en färdighetshandlare som vi gjorde tidigare, men jag vill visa dig möjligheterna att använda en delegat istället.

Steg 3: Implementera delegatprotokollet

För att göra allt detta måste vi genomföra de tre delegerade metoderna i NSURLSessionDownloadDelegate protokoll, URLSession: downloadTask: didFinishDownloadingToURL:, URLSession: downloadTask: didResumeAtOffset: expectedTotalBytes:, och URLSession: downloadTask: downloadTask didWriteData: totalBytesWritten: totalBytesExpectedToWrite:. Genomförandet av varje metod är ganska enkelt. Det är viktigt att notera att vi behöver uppdatera användargränssnittet på huvudtråden med hjälp av GCD (Grand Central Dispatch). Genom att passera noll som tredje argumentet av sessionWithConfiguration: delegat: delegateQueue:, operativsystemet skapade en bakgrundskö för oss. Det här är bra, men det betyder också att vi måste vara medvetna om att delegatsmetoderna är åberopade på en bakgrundstråd istället för huvudtråden. Bygg projektet och kör programmet för att se resultatet av vårt hårda arbete.

 - (void) URLSession: (NSURLSession *) session nedladdningTask: (NSURLSessionDownloadTask *) downloadTask didFinishDownloadingToURL: (NSURL *) plats NSData * data = [NSData dataWithContentsOfURL: location]; dispatch_async (dispatch_get_main_queue (), ^ self.progressView setHidden: YES]; [self.imageView setImage: [UIImage imageWithData: data]];);  - (void) URLSession: (NSURLSession *) session nedladdningTask: (NSURLSessionDownloadTask *) downloadTask didResumeAtOffset: (int64_t) fileOffset expectedTotalBytes: (int64_t) expectedTotalBytes  - (void) URLSession: (NSURLSession *) session nedladdningTask: (NSURLSessionDownloadTask *) downloadTask didWriteData: (int64_t) bytesWritten totalBytesWritten: (int64_t) totalBytesWritten totalBytesExpectedToWrite: (int64_t) totalBytesExpectedToWrite float progress = (double) totalBytesWritten / (double) totalBytesExpectedToWrite; dispatch_async (dispatch_get_main_queue (), ^ [self.progressView setProgress: progress];); 

Slutsats

Med dessa två exempel borde du ha en grundläggande förståelse för grunden för NSURLSession API, hur det jämförs med NSURLConnection, och vad dess fördelar är. I nästa del av denna serie tittar vi på mer avancerade funktioner i NSURLSession.