iphone nsurlconnection grand-central-dispatch

iphone - NSURLConnection y grand central dispatch



grand-central-dispatch (3)

¿Es recomendable cerrar NSUrlConnection en un bloque de estilo gcd y ejecutarlo en una cola low_priority?

Necesito asegurarme de que mis conexiones no están sucediendo en el hilo principal y las conexiones deben ser asincrónicas. También necesito varias solicitudes simultáneas para ir a la vez.

Si tomo la ruta gcd, no estoy seguro de qué subproceso se invocan los métodos NSUrlConnectionDelegate.

NSURLConnection depende de los delegados, por lo que una vez que se completa la conexión, cualquier clase contenedora que lo maneje necesitará invocar a su llamador. No estoy seguro de cómo lidiar con todas las varias devoluciones de llamada que se invocan cuando se inicia / finaliza el trabajo de conexión:

- (void)connection:(NSURLConnection *)aConnection didReceiveResponse:(NSURLResponse *)response; - (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)incrementalData; - (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error; - (void)connectionDidFinishLoading:(NSURLConnection *)connection;

¿Debo simplemente llamar a las versiones sincrónicas pero envueltas en bloques gcd? Y si quiero cancelar una llamada, ¿usar ''dispatch_suspend''?

dispatch_async(queue,^{ NSString* result = [self mySynchronousHttp:someURLToInvoke]; }); // If I need to cancel dispatch_suspend(queue);


Cree una NSOperation simultánea en la que ejecute su NSURLConnection asincrónica.


Echa un vistazo a este bloque de código:

-(void)getDataFromServer { NSDictionary *dicParams = [NSDictionary dictionaryWithObjectsAndKeys: userId, kUserID, pageIndex,kPageIndex, nil]; NSString *yourURL = [self addQueryStringToUrlString:[NSString stringWithFormat:@"%@/%@",_PATH_,apiName] withDictionary:dicParams]; NSString *queue_id = @"_queue_id_"; dispatch_queue_t queue = dispatch_queue_create([queue_id UTF8String], 0); dispatch_queue_t main = dispatch_get_main_queue(); dispatch_async(queue, ^{ NSMutableURLRequest *theRequest = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:yourURL] cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:60.0]; [theRequest setHTTPMethod:@"GET"]; [theRequest setValue:@"application/json" forHTTPHeaderField:@"Accept"]; [theRequest setValue:@"application/json" forHTTPHeaderField:@"Content-Type"]; NSError *serviceError = nil; NSURLResponse *serviceResponse = nil; NSData *dataResponse = [NSURLConnection sendSynchronousRequest:theRequest returningResponse:&serviceResponse error:&serviceError]; if(serviceError) { dispatch_sync(main, ^{ // Update your UI if(serviceError.code == -1012){ // Log error }else{ // Log error } }); } else { NSError *jsonError = nil; id dataObject = [NSJSONSerialization JSONObjectWithData:dataResponse options:kNilOptions error:&jsonError]; NSMutableArray *arrResponse = (NSMutableArray *)dataObject; dispatch_sync(main, ^{ // Update your UI [yourTableView reloadData]; }); } }); } +(NSString*)addQueryStringToUrlString:(NSString *)urlString withDictionary:(NSDictionary *)dictionary { NSMutableString *urlWithQuerystring = [[NSMutableString alloc] initWithString:urlString]; for (id key in dictionary) { NSString *keyString = [key description]; NSString *valueString = [[dictionary objectForKey:key] description]; if ([urlWithQuerystring rangeOfString:@"?"].location == NSNotFound) { [urlWithQuerystring appendFormat:@"?%@=%@", [self urlEscapeString:keyString], [self urlEscapeString:valueString]]; } else { [urlWithQuerystring appendFormat:@"&%@=%@", [self urlEscapeString:keyString], [self urlEscapeString:valueString]]; } } return urlWithQuerystring; } +(NSString*)urlEscapeString:(NSString *)unencodedString { CFStringRef originalStringRef = (__bridge_retained CFStringRef)unencodedString; NSString *s = (__bridge_transfer NSString *)CFURLCreateStringByAddingPercentEscapes(NULL,originalStringRef, NULL, NULL,kCFStringEncodingUTF8); CFRelease(originalStringRef); return s; }


Te recomiendo que veas WWDC Sessions sobre la aplicación de red en iPhone OS.

  • WWDC 2010 Session 207 - Aplicaciones de red para iPhone OS, Parte 1
  • WWDC 2010 Session 208 - Aplicaciones de red para iPhone OS, Parte 2

El conferenciante dijo

"Threads Are Evil ™"

para la programación en red y se recomienda utilizar la programación de red asíncrona con RunLoop. Use el hilo de fondo (Grand Concurrent Discurch Concurrent Queue) para el procesamiento de datos seguro para subprocesos, no para la programación en red.

Por cierto, también vale la pena ver las sesiones de Blocks y Grand Central Dispatch.

  • WWDC 2010 Session 206 - Introducción a los bloques y Grand Central Dispatch en iPhone
  • WWDC 2010 Session 211 - Simplificación del desarrollo de aplicaciones de iPhone con Grand Central Dispatch

Escribí una clase contenedora para NSURLConnection asíncrona.

AsyncURLConnection.h

#import <Foundation/Foundation.h> typedef void (^completeBlock_t)(NSData *data); typedef void (^errorBlock_t)(NSError *error); @interface AsyncURLConnection : NSObject { NSMutableData *data_; completeBlock_t completeBlock_; errorBlock_t errorBlock_; } + (id)request:(NSString *)requestUrl completeBlock:(completeBlock_t)completeBlock errorBlock:(errorBlock_t)errorBlock; - (id)initWithRequest:(NSString *)requestUrl completeBlock:(completeBlock_t)completeBlock errorBlock:(errorBlock_t)errorBlock; @end

AsyncURLConnection.m

#import "AsyncURLConnection.h" @implementation AsyncURLConnection + (id)request:(NSString *)requestUrl completeBlock:(completeBlock_t)completeBlock errorBlock:(errorBlock_t)errorBlock { return [[[self alloc] initWithRequest:requestUrl completeBlock:completeBlock errorBlock:errorBlock] autorelease]; } - (id)initWithRequest:(NSString *)requestUrl completeBlock:(completeBlock_t)completeBlock errorBlock:(errorBlock_t)errorBlock { if ((self=[super init])) { data_ = [[NSMutableData alloc] init]; completeBlock_ = [completeBlock copy]; errorBlock_ = [errorBlock copy]; NSURL *url = [NSURL URLWithString:requestUrl]; NSURLRequest *request = [NSURLRequest requestWithURL:url]; [NSURLConnection connectionWithRequest:request delegate:self]; } return self; } - (void)dealloc { [data_ release]; [completeBlock_ release]; [errorBlock_ release]; [super dealloc]; } - (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response { [data_ setLength:0]; } - (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data { [data_ appendData:data]; } - (void)connectionDidFinishLoading:(NSURLConnection *)connection { completeBlock_(data_); } - (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error { errorBlock_(error); } @end

Cómo usar la clase AsyncURLConnection.

/* * AsyncURLConnection -request:completeBlock:errorBlock: have to be called * from Main Thread because it is required to use asynchronous API with RunLoop. */ [AsyncURLConnection request:url completeBlock:^(NSData *data) { /* success! */ dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ /* process downloaded data in Concurrent Queue */ dispatch_async(dispatch_get_main_queue(), ^{ /* update UI on Main Thread */ }); }); } errorBlock:^(NSError *error) { /* error! */ }];