Tengo un montón de código repetido en mi clase que se parece a lo siguiente:
NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request
delegate:self];
El problema con las solicitudes asincrónicas es que cuando tienes varias solicitudes y tienes un delegado asignado para tratarlas a todas como una entidad, muchas ramificaciones y códigos desagradables comienzan a formularse:
¿Qué tipo de datos estamos recuperando? Si contiene esto, haz eso, de lo contrario haz otro. Creo que sería útil poder etiquetar estas solicitudes asincrónicas, como si pudieras etiquetar vistas con ID.
Tenía curiosidad por saber qué estrategia es más eficiente para administrar una clase que maneja múltiples solicitudes asincrónicas.
fuente
[NSMapTable weakToStrongObjectsMapTable]
lugar deCFMutableDictionaryRef
ay ahorrar la molestia. Funcionó bien para mí.Tengo un proyecto en el que tengo dos NSURLConnections distintas y quería usar el mismo delegado. Lo que hice fue crear dos propiedades en mi clase, una para cada conexión. Luego, en el método de delegado, verifico si de qué conexión es
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data { if (connection == self.savingConnection) { [self.savingReturnedData appendData:data]; } else { [self.sharingReturnedData appendData:data]; } }
Esto también me permite cancelar una conexión específica por nombre cuando sea necesario.
fuente
Subclasificar NSURLConnection para contener los datos es limpio, menos código que algunas de las otras respuestas, es más flexible y requiere menos atención sobre la administración de referencias.
// DataURLConnection.h #import <Foundation/Foundation.h> @interface DataURLConnection : NSURLConnection @property(nonatomic, strong) NSMutableData *data; @end // DataURLConnection.m #import "DataURLConnection.h" @implementation DataURLConnection @synthesize data; @end
Úselo como lo haría con NSURLConnection y acumule los datos en su propiedad de datos:
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response { ((DataURLConnection *)connection).data = [[NSMutableData alloc] init]; } - (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data { [((DataURLConnection *)connection).data appendData:data]; }
Eso es.
Si desea ir más allá, puede agregar un bloque para que sirva como devolución de llamada con solo un par de líneas más de código:
// Add to DataURLConnection.h/.m @property(nonatomic, copy) void (^onComplete)();
Configúrelo así:
DataURLConnection *con = [[DataURLConnection alloc] initWithRequest:request delegate:self startImmediately:NO]; con.onComplete = ^{ [self myMethod:con]; }; [con start];
e invocarlo cuando la carga finalice así:
- (void)connectionDidFinishLoading:(NSURLConnection *)connection { ((DataURLConnection *)connection).onComplete(); }
Puede extender el bloque para aceptar parámetros o simplemente pasar DataURLConnection como un argumento al método que lo necesita dentro del bloque no-args como se muestra
fuente
ESTA NO ES UNA RESPUESTA NUEVA. POR FAVOR, DÉJAME MOSTRARLE CÓMO LO HICE
Para distinguir diferentes NSURLConnection dentro de los métodos delegados de la misma clase, uso NSMutableDictionary, para configurar y eliminar NSURLConnection, usando su
(NSString *)description
clave.El objeto que elegí
setObject:forKey
es la URL única que se usa para iniciarNSURLRequest
losNSURLConnection
usos.Una vez establecido NSURLConnection se evalúa en
-(void)connectionDidFinishLoading:(NSURLConnection *)connection, it can be removed from the dictionary. // This variable must be able to be referenced from - (void)connectionDidFinishLoading:(NSURLConnection *)connection NSMutableDictionary *connDictGET = [[NSMutableDictionary alloc] init]; //...// // You can use any object that can be referenced from - (void)connectionDidFinishLoading:(NSURLConnection *)connection [connDictGET setObject:anyObjectThatCanBeReferencedFrom forKey:[aConnectionInstanceJustInitiated description]]; //...// // At the delegate method, evaluate if the passed connection is the specific one which needs to be handled differently if ([[connDictGET objectForKey:[connection description]] isEqual:anyObjectThatCanBeReferencedFrom]) { // Do specific work for connection // } //...// // When the connection is no longer needed, use (NSString *)description as key to remove object [connDictGET removeObjectForKey:[connection description]];
fuente
Un enfoque que he adoptado es no utilizar el mismo objeto que el delegado para cada conexión. En su lugar, creo una nueva instancia de mi clase de análisis para cada conexión que se activa y configuro el delegado en esa instancia.
fuente
Prueba mi clase personalizada, MultipleDownload , que se encarga de todo esto por ti.
fuente
Normalmente creo una variedad de diccionarios. Cada diccionario tiene un poco de información de identificación, un objeto NSMutableData para almacenar la respuesta y la conexión en sí. Cuando se activa un método delegado de conexión, busco el diccionario de la conexión y lo manejo en consecuencia.
fuente
Una opción es simplemente crear una subclase de NSURLConnection y agregar una etiqueta o un método similar. El diseño de NSURLConnection es intencionalmente muy básico, por lo que es perfectamente aceptable.
O quizás podría crear una clase MyURLConnectionController que sea responsable de crear y recopilar los datos de una conexión. Entonces solo tendría que informar a su objeto controlador principal una vez que finalice la carga.
fuente
en iOS5 y superior, puede usar el método de clase
sendAsynchronousRequest:queue:completionHandler:
No es necesario realizar un seguimiento de las conexiones, ya que la respuesta regresa en el controlador de finalización.
fuente
Me gusta ASIHTTPRequest .
fuente
Como se señaló en otras respuestas, debe almacenar connectionInfo en algún lugar y buscarlos por conexión.
El tipo de datos más natural para esto es
NSMutableDictionary
, pero no se puede aceptarNSURLConnection
como claves ya que las conexiones no se pueden copiar.Otra opción para usar
NSURLConnections
como clavesNSMutableDictionary
es usarNSValue valueWithNonretainedObject]
:NSMutableDictionary* dict = [NSMutableDictionary dictionary]; NSValue *key = [NSValue valueWithNonretainedObject:aConnection] /* store: */ [dict setObject:connInfo forKey:key]; /* lookup: */ [dict objectForKey:key];
fuente
Decidí subclasificar NSURLConnection y agregar una etiqueta, un delegado y un NSMutabaleData. Tengo una clase DataController que maneja toda la gestión de datos, incluidas las solicitudes. Creé un protocolo DataControllerDelegate, para que las vistas / objetos individuales puedan escuchar el DataController para averiguar cuándo finalizaron sus solicitudes y, si es necesario, cuánto se ha descargado o qué errores. La clase DataController puede usar la subclase NSURLConnection para iniciar una nueva solicitud y guardar al delegado que desea escuchar el DataController para saber cuándo ha finalizado la solicitud. Esta es mi solución de trabajo en XCode 4.5.2 e ios 6.
El archivo DataController.h que declara el protocolo DataControllerDelegate). El DataController también es un singleton:
@interface DataController : NSObject @property (strong, nonatomic)NSManagedObjectContext *context; @property (strong, nonatomic)NSString *accessToken; +(DataController *)sharedDataController; -(void)generateAccessTokenWith:(NSString *)email password:(NSString *)password delegate:(id)delegate; @end @protocol DataControllerDelegate <NSObject> -(void)dataFailedtoLoadWithMessage:(NSString *)message; -(void)dataFinishedLoading; @end
Los métodos clave en el archivo DataController.m:
-(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response { NSURLConnectionWithDelegate *customConnection = (NSURLConnectionWithDelegate *)connection; NSLog(@"DidReceiveResponse from %@", customConnection.tag); [[customConnection receivedData] setLength:0]; } -(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data { NSURLConnectionWithDelegate *customConnection = (NSURLConnectionWithDelegate *)connection; NSLog(@"DidReceiveData from %@", customConnection.tag); [customConnection.receivedData appendData:data]; } -(void)connectionDidFinishLoading:(NSURLConnection *)connection { NSURLConnectionWithDelegate *customConnection = (NSURLConnectionWithDelegate *)connection; NSLog(@"connectionDidFinishLoading from %@", customConnection.tag); NSLog(@"Data: %@", customConnection.receivedData); [customConnection.dataDelegate dataFinishedLoading]; } -(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error { NSURLConnectionWithDelegate *customConnection = (NSURLConnectionWithDelegate *)connection; NSLog(@"DidFailWithError with %@", customConnection.tag); NSLog(@"Error: %@", [error localizedDescription]); [customConnection.dataDelegate dataFailedtoLoadWithMessage:[error localizedDescription]]; }
Y para iniciar una solicitud:
[[NSURLConnectionWithDelegate alloc] initWithRequest:request delegate:self startImmediately:YES tag:@"Login" dataDelegate:delegate];
NSURLConnectionWithDelegate.h: @protocol DataControllerDelegate;
@interface NSURLConnectionWithDelegate : NSURLConnection @property (strong, nonatomic) NSString *tag; @property id <DataControllerDelegate> dataDelegate; @property (strong, nonatomic) NSMutableData *receivedData; -(id)initWithRequest:(NSURLRequest *)request delegate:(id)delegate startImmediately:(BOOL)startImmediately tag:(NSString *)tag dataDelegate:(id)dataDelegate; @end
Y NSURLConnectionWithDelegate.m:
#import "NSURLConnectionWithDelegate.h" @implementation NSURLConnectionWithDelegate -(id)initWithRequest:(NSURLRequest *)request delegate:(id)delegate startImmediately:(BOOL)startImmediately tag:(NSString *)tag dataDelegate:(id)dataDelegate { self = [super initWithRequest:request delegate:delegate startImmediately:startImmediately]; if (self) { self.tag = tag; self.dataDelegate = dataDelegate; self.receivedData = [[NSMutableData alloc] init]; } return self; } @end
fuente
Cada NSURLConnection tiene un atributo hash, puede discriminar todo por este atributo.
Por ejemplo, necesito mantener cierta información antes y después de la conexión, por lo que mi RequestManager tiene un NSMutableDictionary para hacer esto.
Un ejemplo:
// Make Request NSURLRequest *request = [NSURLRequest requestWithURL:url]; NSURLConnection *c = [[NSURLConnection alloc] initWithRequest:request delegate:self]; // Append Stuffs NSMutableDictionary *myStuff = [[NSMutableDictionary alloc] init]; [myStuff setObject:@"obj" forKey:@"key"]; NSNumber *connectionKey = [NSNumber numberWithInt:c.hash]; [connectionDatas setObject:myStuff forKey:connectionKey]; [c start];
Después de la solicitud:
- (void)connectionDidFinishLoading:(NSURLConnection *)connection { NSLog(@"Received %d bytes of data",[responseData length]); NSNumber *connectionKey = [NSNumber numberWithInt:connection.hash]; NSMutableDictionary *myStuff = [[connectionDatas objectForKey:connectionKey]mutableCopy]; [connectionDatas removeObjectForKey:connectionKey]; }
fuente