Creazione di reti semplificata con AFNetworking

Il networking è difficile. Ci sono varie parti mobili coinvolte e molti fattori devono essere considerati per farlo funzionare. Fortunatamente nel tempo è emersa una serie di librerie open-source per semplificare il networking. AFNetworking, creato e gestito dal popolo di Gowalla, è una di queste librerie. Questo tutorial ti introdurrà al framework AFNetworking mentre mostrerai anche come eseguire query sull'API di iTunes Store!

In questo tutorial, ti presenterò a AFNetworking e ti mostrerò uno spaccato di ciò che questa biblioteca ha da offrire. Dopo aver trascorso alcuni minuti con questa libreria, noterai che è stata progettata pensando alla facilità d'uso. Non solo accelera il tuo sviluppo, ma si prenderà cura anche di molte mansioni di networking minuziose. Creeremo una semplice applicazione che interroga iTunes Store per i film che corrispondono al termine di ricerca "harry". I risultati della nostra query verranno visualizzati in una vista tabella.


Sintesi del progetto

L'applicazione che stiamo per compilare query sull'API di ricerca di iTunes Store. In particolare, cerchiamo iTunes Store per i film che corrispondono al termine di ricerca "harry". Se la nostra query ha esito positivo, elaboriamo i risultati e li visualizziamo in una vista tabella. Ogni riga rappresenta un film con un titolo, un regista e una miniatura che mostra la grafica del film. Pronto? Iniziamo.


Impostazione del progetto

Prima di sporcarci le mani con AFNetworking, dobbiamo creare una base di base. Ciò significa impostare il nostro progetto, creare una vista tabella e aggiungere una vista indicatore di attività. Mostreremo l'indicatore di attività quando la nostra richiesta viene elaborata da iTunes Store. Ciò fornirà all'utente quel prezioso extra di feedback che viene spesso trascurato.

Crea un nuovo progetto in Xcode selezionando il Applicazione vista singola modello dall'elenco di modelli. Dai un nome alla tua domanda NetworkingIsFun, inserisci un identificativo aziendale, imposta "iPhone" per la famiglia di dispositivi e deseleziona "Usa Storyboard". Puoi lasciare il resto intatto, ma assicurati che Utilizzare il conteggio di riferimento automatico è controllato Dillo a Xcode dove vuoi salvare il tuo progetto e premi "Salva".


Aggiungere la tabella e le visualizzazioni dell'indicatore di attività

Anche se Interface Builder è ottimo, spesso costruisco le mie interfacce in modo programmatico, e questo è ciò che faremo anche in questo tutorial. Ci permetterà di concentrarci sul codice senza essere distratto da Interface Builder. Aperto ViewController.h e creare tre variabili di istanza (ivars) e le proprietà per questi ivars. Dato che lavoreremo con una vista tabella, non dimenticare di rendere il tuo controller di visualizzazione conforme al UITableViewDataSource e UITableViewDelegate protocolli. Il file di intestazione del tuo controller di visualizzazione dovrebbe ora essere simile a quello qui sotto:

 #importare  @interface ViewController: UIViewController  UITableView * _tableView; UIActivityIndicatorView * _activityIndicatorView; NSArray * _movies;  @property (nonatomic, retain) UITableView * tableView; @property (nonatomic, retain) UIActivityIndicatorView * activityIndicatorView; @property (nonatomic, retain) film NSArray *; @fine

Se sei confuso dall'uso dei caratteri di sottolineatura, ti consiglio di leggere qui. Sentiti libero di omettere i trattini bassi se pensi che ti sembrino brutti o ti faccia sentire a disagio. Oltre ai caratteri di sottolineatura, non ci dovrebbero essere sorprese. Dichiariamo il nostro UITableView e UIActivityIndicatorView nonché un NSArray, che utilizzeremo per memorizzare i risultati che otteniamo dalla nostra query di ricerca. Pronto? Andiamo al file di implementazione del nostro controller di visualizzazione.

Dal momento che abbiamo dichiarato tre proprietà nel nostro file di intestazione, dobbiamo sintetizzare i loro accessor in ViewController.m. Di nuovo, se i underscore ti confondono, puoi lasciarli fuori.

 @synthesize tableView = _tableView, activityIndicatorView = _activityIndicatorView, movies = _movies;

Nel nostro viewDidLoad metodo, abbiamo impostato la nostra tabella e le visualizzazioni degli indicatori di attività. Il codice sotto dovrebbe essere auto-esplicativo per la maggior parte. Se non hai mai configurato una vista tabella senza usare Interface Builder, potresti vedere alcune righe che non ti sono familiari. Invece di collegare la vista tabella in Interface Builder, ci occupiamo di questo in viewDidLoad metodo. Dopo aver chiamato la superclasse ' viewDidLoad metodo, inizializziamo la nostra vista tabella con una cornice e uno stile, e impostiamo il nostro controller di visualizzazione come origine dati e delegato della nostra vista tabella. Quando la nostra applicazione si avvia, nascondiamo la nostra vista tabella poiché non abbiamo nulla da mostrare finché la nostra query non ha restituito alcun risultato. Prima di aggiungere la vista tabella come sottoview alla vista del nostro controller di visualizzazione, abbiamo impostato la sua maschera di autoresizzazione. La maschera di autoresizzazione definisce come ridimensionare la vista tabella se la vista genitore - la vista del controller di visualizzazione a cui aggiungiamo la vista tabella - cambia di dimensioni. Questo accade quando il dispositivo viene ruotato, per esempio. Confuso? Non preoccuparti per questo Non è importante per questa applicazione.

 - (void) viewDidLoad [super viewDidLoad]; // Impostazione della vista tabella self.tableView = [[UITableView alloc] initWithFrame: CGRectMake (0.0, 0.0, self.view.size.width, self.view.bounds.size.height) style: UITableViewStylePlain]; self.tableView.dataSource = self; self.tableView.delegate = self; self.tableView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; self.tableView.hidden = YES; [self.view addSubview: self.tableView]; // Impostazione dell'indicatore di attività Visualizza self.activityIndicatorView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle: UIActivityIndicatorViewStyleGray]; self.activityIndicatorView.hidesWhenStopped = YES; self.activityIndicatorView.center = self.view.center; [self.view addSubview: self.activityIndicatorView]; [self.activityIndicatorView startAnimating]; // Inizializzazione origine dati self.movies = [[NSArray alloc] init]; 

Configurare la visualizzazione dell'indicatore di attività è altrettanto semplice. Inizializziamo la vista dell'indicatore di attività con uno stile predefinito, impostiamo la sua hidesWhenStopped proprietà a , e posizionarlo al centro della sua vista genitore. Dopo averlo aggiunto alla vista del controller della vista, iniziamo ad animare l'indicatore di attività. L'indicatore di attività si visualizzerà automaticamente da quando lo abbiamo impostato hidesWhenStopped proprietà a SÌ.

Alla fine del nostro viewDidLoad metodo, inizializziamo il film array. Lo useremo in seguito per memorizzare i risultati della nostra query di ricerca.


Protocolli di visualizzazione tabella

Per questo tutorial, implementeremo solo due metodi del protocollo di origine dati della vista tabella. Sono richiesti entrambi questi metodi. Questa è l'implementazione minima richiesta per ottenere la visualizzazione della tabella attiva e in esecuzione. Anche se abbiamo impostato il nostro controller di visualizzazione come delegato della vista tabella, non utilizzeremo nessuno dei metodi delegati nella nostra applicazione. Se hai già utilizzato una vista tabella, non troverai sorprese nelle implementazioni del metodo mostrate di seguito.

 - (NSInteger) tableView: (UITableView *) tableView numberOfRowsInSection: (NSInteger) section if (self.movies && self.movies.count) return self.movies.count;  else return 0;  - (UITableViewCell *) tableView: (UITableView *) tableView cellForRowAtIndexPath: (NSIndexPath *) indexPath static NSString * cellID = @ "Cell Identifier"; UITableViewCell * cell = [tableView dequeueReusableCellWithIdentifier: cellID]; if (! cell) cell = [[UITableViewCell alloc] initWithStyle: UITableViewCellStyleSubtitle riuseIdentifier: cellID];  restituisci cella; 

Nel tableView: numberOfRowsInSection:, dobbiamo restituire il numero di righe in ogni sezione della vista tabella. Nel nostro esempio, la vista tabella contiene solo una sezione (predefinita), che rende tutto un po 'più semplice. Per prima cosa controlliamo se il nostro film la variabile non è nulla e verifichiamo che contenga elementi. Se entrambi questi requisiti sono soddisfatti, restituiamo il numero di elementi nell'array film, in caso contrario, restituiamo zero.

Nostro tableView: cellForRowAtIndexPath: il metodo è di base pure. Iniziamo chiedendo alla nostra tabella di vedere se c'è una cella che possiamo riutilizzare. Se questo non è il caso, creiamo una nuova cella con uno identificatore di stile e riutilizzo. Finiamo la nostra implementazione restituendo la nostra cella. Questo lo farà per ora. Ora puoi creare ed eseguire la tua applicazione. Se hai seguito correttamente i passaggi, dovresti vedere l'indicatore di attività girare come un matto e la vista tabella dovrebbe essere nascosta.


Aggiunta di AFNetworking al Mix

Aggiungere AFNetworking al tuo progetto è facile come torta. Inizia scaricando la libreria da GitHub ed estrai l'archivio. L'archivio contiene una cartella denominata AFNetworking, che contiene i file sorgente che dobbiamo includere nel nostro progetto. Trascina l'intera cartella nel tuo progetto Xcode e assicurati di controllare Copia gli elementi nella cartella del gruppo di destinazione (se necessario) e aggiungi anche i file sorgente al tuo obiettivo.

Dopo aver aggiunto la libreria AFNetworking al tuo progetto, crea ed esegui la tua applicazione e guarda come tutto cade a pezzi. Cosa è successo al nostro progetto? Perché riceviamo tutti questi avvisi ed errori? Quando abbiamo impostato il nostro progetto Xcode, abbiamo abilitato Conteggio di riferimento automatico (ARC). Al momento della scrittura, la libreria di AFNetworking non utilizza ARC. Non ti preoccupare, tuttavia, possiamo ancora usare questa libreria ordinata con pochissimo sforzo. Tutto quello che dobbiamo fare è dire al compilatore che tutti i file sorgente della libreria di AFNetworking non usano ARC. Questo è tutto.

Come facciamo questo? Seleziona il tuo progetto nel Project Navigator e seleziona il tuo obiettivo. Clicca il Costruisci fasi scheda nella barra di navigazione in alto e aprire il Compila fonti cassetto. Questa tabella mostra tutti i file sorgente che il compilatore compilerà in fase di compilazione. La colonna di sinistra mostra i nomi dei file e la colonna di destra mostra i flag di cui il compilatore dovrebbe essere a conoscenza.

Puoi vedere questi flag come istruzioni o messaggi per il compilatore. Tutto quello che devi fare è aggiungere un flag del compilatore a ciascun file sorgente della libreria di AFNetworking. Per fare ciò, selezionare un file sorgente dall'elenco e fare doppio clic sulla cella nella colonna di destra. Apparirà una piccola finestra in cui è possibile aggiungere uno o più flag del compilatore. Nel nostro caso, digita semplicemente -fno-objc-arc e fare clic Fatto. Questo flag dice al compilatore che il file sorgente non usa ARC. Assicurati di aggiungere questo flag a tutti e dieci i file sorgente della libreria di AFNetworking.


Interrogare l'API di ricerca di iTunes Store

AFNetworking è una libreria che può fare molto per te, ma oggi useremo solo due caratteristiche chiare. Prima di poter iniziare a utilizzare le classi AFNetworking, è necessario aggiungere la seguente istruzione import appena sotto la prima istruzione import nel file di implementazione del proprio controller di visualizzazione.

 #import "AFNetworking.h"

Questa dichiarazione di importazione ci darà accesso a tutte le classi di AFNetworking. Tornate al nostro controller di visualizzazione viewDidLoad metodo e aggiungere il seguente frammento immediatamente dopo l'inizializzazione del film schieramento.

 NSURL * url = [[NSURL alloc] initWithString: @ "http://itunes.apple.com/search?term=harry&country=us&entity=movie"]; NSURLRequest * request = [[NSURLRequest alloc] initWithURL: url]; AFJSONRequestOperation * operation = [AFJSONRequestOperation JSONRequestOperationWithRequest: richiesta riuscita: ^ (richiesta NSURLRequest *, risposta NSHTTPURLResponse *, id JSON) NSLog (@ "% @", JSON);  errore: ^ (richiesta NSURLRequest *, risposta NSHTTPURLResponse *, errore NSError *, id JSON) NSLog (@ "Richiesta non riuscita con errore:% @,% @", errore, error.userInfo); ]; [inizio operazione];

Lascia che ti spieghi cosa sta succedendo. Nella prima riga, creiamo NSURL per la nostra richiesta. La stringa che utilizziamo nell'inizializzazione è conforme al formato previsto dall'API di ricerca di iTunes Store. La sintassi dell'API di ricerca è abbastanza semplice: il termine che stiamo cercando è "harry", limitiamo la nostra ricerca a iTunes Store negli Stati Uniti e stiamo cercando solo film. Facile, giusto?

Successivamente, inizializziamo un NSURLRequest e passiamo nel NSURL appena creato. Quindi viene attivato AFNetworking. AFNetworking contiene alcune classi molto specializzate che rendono il nostro lavoro molto semplice. Quello che usiamo qui è AFJSONRequestOperation. Questa è una classe progettata per recuperare e analizzare i dati JSON in background. Come suggerisce il nome, questa classe è una sottoclasse di NSOperation o, per essere più precisi, una delle superclassi di questa classe eredita da NSOperation. La classe consente di recuperare i dati richiesti e analizza anche la risposta JSON. Ciò significa che non dobbiamo occuparci di JSON raw. I dati restituiti sono pronti per l'uso nella tua applicazione. AFNetworking utilizza il parser JSON integrato su iOS 5 e torna al proprio parser JSON per versioni iOS precedenti.

L'utilizzo di AFJSONRequestOperation è semplice poiché ha un solo metodo di classe. Questo metodo di classe accetta tre argomenti: (1) un NSURLRequest, (2) un blocco di successo, eseguito quando la richiesta ha esito positivo e (3) un blocco di errore, eseguito quando la richiesta non riesce. Se i blocchi sono nuovi per te o non ti senti a tuo agio a utilizzarli, ti consiglio di leggere il tutorial di Collin Ruffenach sui blocchi e la numerazione su Mobiletuts +. Il blocco di successo accetta tre argomenti: (1) il nostro NSURLRequest, (2) il NSHTTPURLResponse della nostra richiesta e (3) un oggetto JSON analizzato. Il blocco di errore è quasi identico. L'unica differenza è che ci vuole un argomento addizionale, un NSError che contiene più informazioni su cosa è andato storto nel caso in cui la nostra richiesta fallisse.

A scopo di test, registriamo l'oggetto JSON analizzato per vedere cosa ci restituisce l'API di ricerca di iTunes Store. Inoltre, registriamo anche l'errore nel blocco degli errori nel caso in cui la nostra richiesta dovesse fallire. Prima di costruire ed eseguire nuovamente la nostra applicazione, dobbiamo avviare l'operazione chiamando inizio sul nostro oggetto operativo. Crea ed esegui la tua applicazione e dai un'occhiata all'output nella console.

Se tutto è andato bene, vedrai i risultati della nostra richiesta registrati nella console. L'oggetto JSON analizzato è un dizionario con due chiavi: (1) resultCount, che contiene il numero di risultati restituiti e (2) il reale risultati come una serie di dizionari. Non solo abbiamo registrato la risposta alla console per vedere se la nostra richiesta ha avuto successo, ora possiamo vedere le chiavi per ogni elemento nell'array dei risultati. Avremo bisogno di queste chiavi per visualizzare alcune informazioni nella nostra vista tabella.


Popolazione della vista tabella

Ora siamo pronti a mostrare i risultati nella nostra vista tabella. Sostituisci l'istruzione del registro nel blocco di successo con lo snippet mostrato di seguito. Iniziamo assegnando la matrice dei risultati dell'oggetto risposta all'array dei filmati. L'unica cosa che rimane da fare è nascondere l'indicatore di attività fermandolo, mostrando la vista tabella e ricaricando la vista tabella con i nuovi dati memorizzati nell'array dei filmati.

 self.movies = [JSON objectForKey: @ "results"]; [self.activityIndicatorView stopAnimating]; [self.tableView setHidden: NO]; [self.tableView reloadData];

Successivamente modifichiamo il tableView: cellForRowAtIndexPath: metodo. Regola la tua implementazione per riflettere quella qui sotto. Dopo aver ottenuto un riferimento a una cella, interrogiamo l'array di filmati per l'elemento corretto e aggiorniamo le etichette della cella con il titolo e il direttore del film. Costruisci ed esegui la tua applicazione.

 - (UITableViewCell *) tableView: (UITableView *) tableView cellForRowAtIndexPath: (NSIndexPath *) indexPath static NSString * cellID = @ "Cell Identifier"; UITableViewCell * cell = [tableView dequeueReusableCellWithIdentifier: cellID]; if (! cell) cell = [[UITableViewCell alloc] initWithStyle: UITableViewCellStyleSubtitle riuseIdentifier: cellID];  NSDictionary * movie = [self.movies objectAtIndex: indexPath.row]; cell.textLabel.text = [movie objectForKey: @ "trackName"]; cell.detailTextLabel.text = [movie objectForKey: @ "artistName"]; cella di ritorno; 

Potresti aver notato che non ci sono miniature da vedere. Risolviamolo aggiungendo tre linee extra al nostro tableView: cellForRowAtIndexPath: metodo. Costruisci ed esegui la tua applicazione.

 NSURL * url = [[allocazione NSURL] initWithString: [movie objectForKey: @ "artworkUrl100"]]; NSData * data = [NSData dataWithContentsOfURL: url]; cell.imageView.image = [[UIImage alloc] initWithData: data];

Hai notato che la nostra vista tabella non scorre uniformemente. Perché? Come ho detto in un precedente tutorial, devi sempre assicurarti che il thread principale della tua applicazione rimanga sensibile. Nell'attuale implementazione del nostro tableView: cellForRowAtIndexPath: metodo, stiamo scaricando le miniature sul thread principale. Ciò significa che l'interfaccia utente non può essere aggiornata fino al termine della richiesta di una miniatura. Le nostre miniature sono minuscole, quindi le richieste non richiedono troppo tempo per essere completate, ma immaginate di adottare lo stesso approccio per le risorse più grandi. L'esperienza dell'utente sarebbe terribile. Anche per la nostra semplice applicazione, l'esperienza dell'utente è inaccettabile. Tuttavia, possiamo porvi rimedio con una funzione molto utile della libreria di AFNetworking.


AFNetworking to the Rescue

I creatori di AFNetworking hanno visto la necessità di scaricare anche le risorse in background. Hanno quindi creato una categoria per UIImageView. Questa categoria consente di scaricare le immagini sullo sfondo con solo due righe di codice. Questa categoria è un vero risparmiatore di vita. Dai uno sguardo allo snippet qui sotto.

 NSURL * url = [[allocazione NSURL] initWithString: [movie objectForKey: @ "artworkUrl100"]]; [cell.imageView setImageWithURL: url placeholderImage: [UIImage imageNamed: @ "placeholder"]];

La prima riga di codice rimane la stessa. Nella seconda riga, diciamo alla vista dell'immagine dove si trova la miniatura passando un NSURL e passiamo in un'immagine segnaposto, che viene mostrata fintanto che la nostra richiesta non ha restituito una risposta. Quant'è fico? Tutto ciò che dobbiamo fare è aggiungere un'immagine segnaposto al nostro progetto. Questa può essere l'immagine che desideri, ma puoi trovare l'immagine che ho usato come segnaposto nel file di download allegato a questo tutorial. Dopo aver aggiunto l'immagine segnaposto, costruisci ed esegui la tua applicazione e verifica da te quanto scorre la vista tabella!


Conclusione

Si noti che la nostra applicazione è molto basilare nella sua esecuzione in quanto non fa alcuna memorizzazione nella cache e possiamo cercare nell'iTunes Store solo il termine "harry" nella sezione film. Tuttavia, con pochissimo sforzo puoi creare un'applicazione per cercare in iTunes in modo più dinamico.

Spero che questo tutorial ti abbia convinto che la libreria AFNetworking è un ottimo strumento da avere nel tuo arsenale. Può fare molto di più di quello che ti ho mostrato in questo post, ma l'obiettivo principale di questo tutorial è quello di farti funzionare con AFNetworking e pronto ad usarlo in uno scenario reale.