La modalità sicuramente più performante per richiamare dei servizi online di back-end da una vostra app è quella delle chiamate asincrone.
1° METODO (con dispatch_async). Il classico metodo in iOS, che definirei “nativo”, è quello che utilizza il dispatch_async:
// Add to top of file #import <;dispatch/dispatch.h>; // Use it dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ NSData* responseData = [NSData dataWithContentsOfURL:[NSURL URLWithString:@"http://tuo-sito/servizio"]]; /* ... your code here ...*/ }); }
Non occorre importare nessuna libreria. Nella responseData vi è la risposta HTTP, da cui potete recuperare i vostri dati. Tale metodo richiama il Grand Central Dispatcher per eseguire la chiamata e ricevere una risposta (asincrona) dal server in background. Intanto, la vostra app continua ad eseguire sul thread principale il lavoro, senza bloccarsi in attesa dei dati del servizio richiamato.
2° METODO (con ASIHTTPRequest ). Il metodo che, invece, preferisco è quello che utilizza l’utilissima libreria ASIHTTPRequest, che ci permette di effettuare in modo semplice chiamate HTTP (sincrone e asincrone) e interagire con servizi REST (vedi l’articolo “La filosofia REST“, su questo blog). E’ una libreria particolarmente utile per effettuare anche upload e download di file, chiamate con autenticazione sicura HTTPS, e molto altro … e vi consiglio vivamente di provarla.
La potete scaricare direttamente dal sito ufficiale: ASIHTTP-request downloads
Come si spiega qui: Setup-Instructions, per installarla nel vostro progetto, occorre importare le seguenti librerie/framework (che trovate direttamente in xCode – click sulla root di progetto >> Build Phases >> Link Binary With Libraries):
- CFNetwork,
- SystemConfiguration
- MobileCoreServices
- libz.dylib (attualmente c’è libz.1.2.5.dylib)
//import libs #import "ASIFormDataRequest.h" /* ... your code in controller ...*/ - (void)fetchedData:(NSData *)responseData { NSArray* json = [NSJSONSerialization JSONObjectWithData:responseData options:kNilOptions error:nil]; NSMutableArray *postTMP = [[NSMutableArray alloc] initWithCapacity:[json count]]; for (NSDictionary *dict in json) { Post *post = [[Post alloc] init]; post.titolo = [dict objectForKey:@"titolo"]; post.articolo = [dict objectForKey:@"articolo"]; post.snippet = [dict objectForKey:@"snippet"]; post.urlImage = [dict objectForKey:@"urlImage"]; post.urlThumb = [dict objectForKey:@"urlThumb"]; [postTMP addObject:post]; } //mi assicuro che l'array non possa essere modificato. self.posts = [postTMP copy]; NSLog(@"posts count: %d",[self.posts count]); [self.tableView performSelectorOnMainThread:@selector(reloadData) withObject:nil waitUntilDone:YES]; } - (void)requestFinished:(ASIHTTPRequest *)request { NSLog(@"Response %d ==>; %@", request.responseStatusCode, [request responseString]); NSData *responseData = request.responseData; [self performSelectorOnMainThread:@selector(fetchedData:) withObject:responseData waitUntilDone:YES]; } - (void)requestFailed:(ASIHTTPRequest *)request { //[progressAlert release]; NSError *error = [request error]; NSLog(@"ERROR %@",error); if ([[request error] code] == ASIConnectionFailureErrorType || [[request error] code] == ASIRequestTimedOutErrorType){ UIAlertView *alert = [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"ERROR", nil) message:NSLocalizedString(@"CONNECTION_FAILED",nil) delegate:self cancelButtonTitle:NSLocalizedString(@"OK",nil) otherButtonTitles:nil]; [alert show]; [alert release]; //return; } else{ UIAlertView *alert = [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"ERROR",nil) message: NSLocalizedString(@"GENERIC_ERROR",nil) delegate:self cancelButtonTitle:NSLocalizedString(@"OK",nil) otherButtonTitles:nil]; [alert show]; [alert release]; //return; } } - (void)viewDidLoad { [super viewDidLoad]; NSURL *url = [NSURL URLWithString:@"http://francescoficetola.it/services/test.php"]; ASIFormDataRequest *myRequest = [ASIFormDataRequest requestWithURL:url]; [myRequest setDefaultResponseEncoding:NSUTF8StringEncoding]; [myRequest setResponseEncoding:NSUTF8StringEncoding]; [myRequest setRequestMethod:@"POST"]; [myRequest setPostValue:@"valueMyParameter" forKey:@"myParameter"]; [myRequest addRequestHeader:@"Accept" value:@"application/json"]; [myRequest addRequestHeader:@"Content-Type" value:@"application/json; charset=UTF-8;"]; [myRequest setDelegate:self]; [myRequest startAsynchronous]; }
- requestFailed: è il metodo che viene richiamato se la risposta non è andata a buon fine. E’ possibile intercettare anche il relativo status code, per visualizzare i relativi messaggi di errore all’utente;
- requestFinished: è il metodo che viene richiamato in caso di ricezione con successo della risposta, raccolta dalla variabile responseData. L’elaborazione di quest’ultima viene effettuata con un metodo (che non fa parte della libreria ASIHTTPRequest) che, in un thread di background, estrae dal JSON una lista di oggetti (in questo esempio, i post di un forum), ricaricandoli poi in una UITableView (con il metodo nativo reloadData).
/* ... */ [request setDelegate:self]; [request setCompletionBlock:^{ NSString *responseString = [request responseString]; NSLog(@"Response: %@", responseString); /* your code here in success case */ }]; [request setFailedBlock:^{ NSError *error = [request error]; NSLog(@"Error: %@", error.localizedDescription); /* your code here in error case */ }]; [request startAsynchronous]; /* ... */

This work by Francesco Ficetola is licensed under a Creative Commons Attribution 4.0 International License.
Based on a work at www.francescoficetola.it.
Permissions beyond the scope of this license may be available at http://www.francescoficetola.it/2012/11/03/ios-come-effettuare-chiamate-asincrone/.