Connessione in rete con NSURLSession parte 1

Dal punto di vista dello sviluppatore, uno dei cambiamenti più significativi in ​​iOS 7 e OS X Mavericks è l'introduzione di NSURLSession. Nonostante NSURLSession può sembrare scoraggiante a prima vista, è importante che tu capisca di cosa si tratta, in che modo si relaziona NSURLConnection, e quali sono le differenze. In questa serie, ti illustrerò i fondamenti di NSURLSession così puoi sfruttare questa nuova tecnologia nelle tue applicazioni.


Perché sostituire NSURLConnection?

La prima domanda che potresti chiederti è perché Apple ha ritenuto necessario presentare NSURLSession mentre siamo perfettamente soddisfatti NSURLConnection. La vera domanda è se tu siamo felice con NSURLConnection. Ti ricordi quella volta in cui ti stavi maledicendo e lanciando cose NSURLConnection? La maggior parte degli sviluppatori di Cocoa sono stati in quel luogo, motivo per cui Apple ha deciso di tornare al tavolo da disegno e creare una soluzione più elegante, più adatta per il web moderno.

Nonostante NSURLSession e NSURLConnection hanno molto in comune in termini di come funzionano, a un livello fondamentale, sono molto diversi. Apple ha creato NSURLSession per assomigliare ai concetti generali di NSURLConnection, ma imparerai nel corso di questa serie NSURLSession è moderno, più facile da usare e costruito pensando al mobile.


Cosa è NSURLSession?

Prima di discutere le differenze tra NSURLSession e NSURLConnection, è una buona idea prima dare un'occhiata più da vicino a cosa NSURLSession è. Nonostante il suo nome, NSURLSession non è solo un'altra classe che puoi usare in un'applicazione iOS o OS X.. NSURLSession è prima di tutto una tecnologia proprio come NSURLConnection è.

Le sessioni sono contenitori

NSURLSession e NSURLConnection entrambi forniscono una API per interagire con vari protocolli, come ad esempio HTTP e HTTPS. L'oggetto di sessione, un'istanza di NSURLSession classe, è ciò che gestisce questa interazione. È un contenitore altamente configurabile con un'API elegante che consente un controllo a grana fine. Offre caratteristiche che sono assenti in NSURLConnection. Inoltre, con NSURLSession, puoi svolgere compiti che semplicemente non sono possibili con NSURLConnection, come l'implementazione della navigazione privata.

Compiti

L'unità di base del lavoro quando si lavora con NSURLSession è il compito, un'istanza di NSURLSessionTask. Esistono tre tipi di attività, attività di dati, carica le attività, e attività di download.

  • Utilizzerai il più delle volte attività di dati, che sono istanze di NSURLSessionDataTask. Le attività dati vengono utilizzate per richiedere dati da un server, come i dati JSON. La principale differenza con le attività di upload e download è che restituiscono i dati direttamente alla tua applicazione anziché passare attraverso il file system. I dati vengono archiviati solo in memoria.
  • Come suggerisce il nome, le attività di caricamento vengono utilizzate per caricare i dati su una destinazione remota. Il NSURLSessionUploadTask è una sottoclasse di NSURLSessionDataTask e si comporta in modo simile. Una delle principali differenze con un'attività di dati normale è che le attività di caricamento possono essere utilizzate in una sessione creata con una configurazione di sessione in background.
  • Scarica compiti, istanze di NSURLSessionDownloadTask, eredita direttamente da NSURLSessionTask. La differenza più significativa con le attività di dati è che un'attività di download scrive la sua risposta direttamente su un file temporaneo. Questo è abbastanza diverso da un normale task di dati che memorizza la risposta in memoria. È possibile Annulla un'attività di download e curriculum vitae in un secondo momento.

Come puoi immaginare, l'asincronicità è un concetto chiave in NSURLSession. Il NSURLSession L'API restituisce i dati richiamando un gestore di completamento o tramite il delegato della sessione. L'API di NSURLSession è stato progettato pensando alla flessibilità, come noterete un po 'più avanti in questo tutorial.

Incontra la famiglia

Come ho detto prima, NSURLSession è sia una tecnologia che una classe con cui lavorerai. Il NSURLSession API ospita un numero di classi, ma NSURLSession è il componente chiave che invia richieste e riceve risposte. La configurazione dell'oggetto di sessione, tuttavia, viene gestita da un'istanza di NSURLSessionConfiguration classe. Il NSURLSessionTask la classe e le sue tre sottoclassi concrete sono le worker e vengono sempre utilizzate in congiunzione con una sessione in quanto è la sessione che crea gli oggetti task.

Delegazione

Tutti e due NSURLSession e NSURLConnection fare molto affidamento sul modello di delega. Il NSURLSessionDelegate protocollo dichiara una manciata di metodi delegati per la gestione degli eventi a livello di sessione. Inoltre, il NSURLSessionTask classe e sottoclassi ciascuna dichiarano un protocollo delegato per la gestione degli eventi a livello di attività.

Vecchi amici

Il NSURLSession L'API si basa sulle classi con le quali hai già familiarità, ad esempio NSURL, NSURLRequest, e NSURLResponse.


Quali sono le differenze??

Come fa NSURLSession differire dalla NSURLConnection? Questa è una domanda importante, perché NSURLConnection non viene deprecato da Apple. Puoi ancora usarlo NSURLConnection nei tuoi progetti. Perché dovresti usare? NSURLSession?

La prima cosa da capire è che il NSURLSession istanza è l'oggetto che gestisce la richiesta e la risposta. Questo è simile a come NSURLConnection funziona, ma la differenza chiave è che la configurazione della richiesta è gestita dall'oggetto session, che è un oggetto longevo. Questo è fatto attraverso il NSURLSessionConfiguration classe. Non solo fornisce il NSURLSession Configurazione API a grana fine attraverso il NSURLSessionConfiguration classe, incoraggia la separazione dei dati (corpo della richiesta) dai metadati. Il NSURLSessionDownloadTask lo illustra bene scrivendo direttamente la risposta al file system.

L'autenticazione è più semplice e gestita in modo più elegante NSURLSession. Il NSURLSession L'API gestisce l'autenticazione in base a una connessione anziché su una base di richiesta, ad esempio NSURLConnection lo fa. Il NSURLSession L'API rende inoltre più conveniente fornire opzioni HTTP e ogni sessione può avere un contenitore di memoria separato a seconda di come si configura la sessione.

Nell'introduzione, te l'ho detto NSURLSession fornisce un'interfaccia moderna, che si integra perfettamente con iOS 7. Un esempio di questa integrazione è NSURLSessionGli upload e i download fuori processo. NSURLSession è ottimizzato per preservare la durata della batteria, supporta la pausa, l'annullamento e la ripresa delle attività, nonché l'API multitasking di UIKit. Di cosa non si deve amare NSURLSession?


Ottenere i piedi bagnati

Passaggio 1: Impostazione del progetto

Una nuova API è appresa al meglio dalla pratica, quindi è il momento di accendere Xcode e bagnarsi i piedi. Avvia Xcode 5, crea un nuovo progetto selezionando Nuovo> Progetto ... dal File menu e selezionare Applicazione vista singola modello dall'elenco di modelli di applicazioni iOS.


Dai un nome al tuo progetto, dì a Xcode dove vorresti salvarlo e premi Creare. Non è necessario mettere il progetto sotto il controllo del codice sorgente.


Passaggio 2: creare un oggetto sessione

Quando si lavora con NSURLSession, è importante capire che l'oggetto di sessione, un'istanza di NSURLSession, è il giocatore di stelle. Gestisce le richieste e le risposte, configura le richieste, gestisce l'archiviazione e lo stato delle sessioni, ecc. La creazione di una sessione può essere effettuata in diversi modi. Il modo più rapido per iniziare è quello di utilizzare NSURLSession'S sharedSession metodo di classe come mostrato di seguito.

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

Creare un sessione oggetto nel controller della vista viewDidLoad metodo come mostrato sopra. Il sessione l'oggetto che abbiamo creato va bene per il nostro esempio, ma probabilmente nella maggior parte dei casi desideri un po 'più di flessibilità. Il sessione l'oggetto che abbiamo appena creato utilizza il globale NSURLCache, NSHTTPCookieStorage, e NSURLCredentialStorage. Ciò significa che funziona in modo abbastanza simile a un'implementazione predefinita di NSURLConnection.

Passaggio 3: creare un'attività di dati

Mettere il sessione oggetto da usare, interrogiamo l'API di ricerca di iTunes Store e cerchiamo il software realizzato da Apple. L'API di ricerca di iTunes Store è facile da usare e non richiede autenticazione, il che lo rende ideale per il nostro esempio.

Per eseguire una query sull'API di ricerca, è necessario inviare una richiesta a https://itunes.apple.com/search e passare alcuni parametri. Come abbiamo visto in precedenza, quando si utilizza il NSURLSession API, una richiesta è rappresentata da un'attività. Per eseguire una query sull'API di ricerca, tutto ciò di cui abbiamo bisogno è un'attività di dati, un'istanza di NSURLSessionDataTask classe. Dai un'occhiata al aggiornato viewDidLoad implementazione mostrata di seguito.

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

Esistono numerosi metodi disponibili per creare un'attività, ma il concetto chiave da comprendere è che il sessione oggetto esegue l'effettiva creazione e configurazione dell'attività. In questo esempio, invochiamo dataTaskWithURL: completionHandler: e passargli un'istanza di NSURL così come un gestore di completamento. Il gestore di completamento accetta tre argomenti, il dati grezzi della risposta (NSData), il oggetto di risposta (NSURLResponse), e un oggetto di errore (NSError). Se la richiesta ha esito positivo, l'oggetto error è zero. Poiché sappiamo che la richiesta restituisce una risposta JSON, creiamo a Fondazione oggetto dal dati oggetto che abbiamo ricevuto e registrare l'output sulla console.

È importante capire che il errore l'oggetto passato al gestore di completamento è solo popolato, non zero, se la richiesta non è riuscita o si è verificato un errore. In altre parole, se la richiesta ha restituito a 404 risposta, la richiesta è riuscita per quanto riguarda le sessioni. Il errore l'oggetto sarà quindi zero. Questo è un concetto importante da comprendere quando si lavora con NSURLSession e NSURLConnection per questo motivo.

Costruisci il progetto ed esegui l'applicazione in iOS Simulator o su un dispositivo fisico e ispeziona la console di Xcode. Nulla viene stampato sulla console. Cosa è andato storto? Come ho detto prima, il NSURLSession L'API supporta la sospensione, l'annullamento e il ripristino di attività o richieste. Questo comportamento è simile a quello di NSOperation e potrebbe ricordarti la libreria di AFNetworking. Un'attività ha a stato proprietà che indica se l'attività è in esecuzione (NSURLSessionTaskStateRunning), sospeso (NSURLSessionTaskStateSuspended), annullamento (NSURLSessionTaskStateCanceling), o completato (NSURLSessionTaskStateCompleted). Quando un oggetto di sessione crea un'attività, l'attività inizia la sua vita nel sospeso stato. Per iniziare l'attività, dobbiamo dirlo a curriculum vitae a chiamata curriculum vitae sull'attività. Aggiorna il viewDidLoad metodo come mostrato di seguito, eseguire l'applicazione ancora una volta e ispezionare l'output nella console. Missione compiuta.

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

Download di una risorsa remota

Nell'esempio precedente, abbiamo utilizzato un gestore di completamento per elaborare la risposta ricevuta dalla richiesta. È anche possibile ottenere lo stesso risultato implementando i protocolli delegati dell'attività. Vediamo cosa serve per scaricare un'immagine sfruttando NSURLSession e il NSURLSessionDownloadTask.

Passaggio 1: creare l'interfaccia utente

Aperto MTViewController.h e creare due prese come mostrato di seguito. Useremo la prima presa, un'istanza di UIImageView, per visualizzare l'immagine scaricata all'utente. La seconda uscita, un'istanza di UIProgressView, mostrerà l'avanzamento dell'attività di download.

 #importare  @interface MTViewController: UIViewController @property (weak, nonatomic) IBOutlet UIImageView * imageView; @property (weak, nonatomic) IBOutlet UIProgressView * progressView; @fine

Apri lo storyboard principale del progetto (Main.storyboard), trascinare a UIImageView istanza alla vista del controller della vista e collegare la presa del controller della vista che abbiamo appena creato nel file di intestazione del controller della vista. Ripeti questo processo per la vista del progresso.


Passaggio 2: creare un'attività di download

In questo esempio, non useremo il sharedSession metodo di classe, perché abbiamo bisogno di configurare il sessione oggetto che useremo per fare la richiesta. Aggiorna l'implementazione di viewDidLoad come mostrato di seguito.

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

Per evitare che l'avviso del compilatore si verifichi, assicurati di conformare il file MTViewController classe al NSURLSessionDelegate e NSURLSessionDownloadDelegate protocolli come mostrato di seguito.

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

Nel viewDidLoad, creiamo un'istanza di NSURLSessionConfiguration classe invocando il defaultSessionConfiguration metodo di classe. Come indicato nella documentazione, utilizzando la configurazione di sessione predefinita, la sessione si comporterà come un'istanza di NSURLConnection nella sua configurazione di default, che va bene per il nostro esempio.

In questo esempio, creiamo a NSURLSession istanza invocando il sessionWithConfiguration: delegato: delegateQueue: metodo di classe e passare il sessionConfiguration oggetto che abbiamo creato un momento fa. Impostiamo il controller della vista come delegato della sessione e passiamo zero come il terzo argomento. Puoi ignorare il terzo argomento per ora. La principale differenza con l'esempio precedente è che impostiamo il sessionedelegato al controller di visualizzazione.

Per scaricare l'immagine, dobbiamo creare un'attività di download. Lo facciamo chiamando downloadTaskWithURL: sul sessione oggetto, passando un'istanza di NSURL, e chiamando curriculum vitae sull'attività di download. Avremmo potuto utilizzare un gestore di completamento come facevamo prima, ma voglio mostrarti le possibilità di usare un delegato.

Passaggio 3: implementare il protocollo delegato

Per far funzionare tutto questo, dobbiamo implementare i tre metodi delegati di NSURLSessionDownloadDelegate protocollo, URLSession: downloadTask: didFinishDownloadingToURL:, URLSession: downloadTask: didResumeAtOffset: expectedTotalBytes:, e URLSession: downloadTask: downloadTask didWriteData: totalBytesWritten: totalBytesExpectedToWrite:. L'implementazione di ciascun metodo è abbastanza semplice. È importante notare che è necessario aggiornare l'interfaccia utente sul thread principale utilizzando GCD (Grand Central Dispatch). Passando zero come il terzo argomento di sessionWithConfiguration: delegato: delegateQueue:, il sistema operativo ha creato una coda in background per noi. Questo va bene, ma significa anche che dobbiamo essere consapevoli del fatto che i metodi delegati vengono richiamati su un thread in background anziché sul thread principale. Costruisci il progetto ed esegui l'applicazione per vedere il risultato del nostro duro lavoro.

 - (void) URLSession: (NSURLSession *) sessione downloadTask: (NSURLSessionDownloadTask *) downloadTask didFinishDownloadingToURL: (NSURL *) posizione NSData * data = [NSData dataWithContentsOfURL: posizione]; dispatch_async (dispatch_get_main_queue (), ^ [self.progressView setHidden: YES]; [self.imageView setImage: [UIImage imageWithData: data]];);  - (void) URLSession: (NSURLSession *) sessione downloadTask: (NSURLSessionDownloadTask *) downloadTask didResumeAtOffset: (int64_t) fileOffset expectedTotalBytes: (int64_t) expectedTotalBytes  - (void) URLSession: (NSURLSession *) session downloadTask: (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];); 

Conclusione

Con questi due esempi, dovresti avere una conoscenza di base dei fondamenti del NSURLSession API, come si confronta NSURLConnection, e quali sono i suoi vantaggi. Nella parte successiva di questa serie, vedremo le funzionalità più avanzate di NSURLSession.