ios - servicio - online pedidos
¿Cómo hacer un pedido por lotes con AFNetworking 2? (5)
Actualmente, NSURLSession
tareas de NSURLSession
no son adecuadas para el mismo tipo de patrones que utilizan las operaciones de solicitud. Vea la respuesta de Mattt Thompson aquí con respecto a este problema.
Respuesta directa: si necesita dependencias o lotes, deberá utilizar las operaciones de solicitud.
Así que estoy reescribiendo una aplicación para iOS 7 con AFNetworking 2.0 y me encuentro con el problema de enviar un lote de solicitudes a la vez y hacer un seguimiento de su progreso. En el antiguo AFNetworking estaba el enqueueBatchOfHTTPRequestOperations:progressBlock:completionBlock:
en AFHTTPClient
, esto está claramente refaccionado y estoy un poco confundido sobre cómo poner en cola múltiples solicitudes.
He creado una subclase de AFHTTPSessionManager
y estoy usando los métodos POST:...
y GET:...
para comunicarme con el servidor. Pero no puedo encontrar nada en el código y / o los documentos para encolar varias solicitudes a la vez como con el antiguo AFHTTPClient
.
Lo único que puedo encontrar es el batchOfRequestOperations:progressBlock:completionBlock:
no batchOfRequestOperations:progressBlock:completionBlock:
método en AFURLConnectionOperation
, pero se parece a la forma de iOS 6 de hacerlo.
Claramente, me estoy perdiendo algo en el nuevo concepto de NSURLSession
que debo usar para realizar solicitudes por lotes o revisar una nueva función de AFNetworking. Espero que alguien pueda ayudarme en el camino correcto aquí!
tl; dr: ¿Cómo puedo enviar un lote de solicitudes con mi subclase AFHTTPSessionManager
?
En AFNetworking 2.0, AFHTTPClient
se ha dividido en AFHTTPRequestOperationManager
y AFHTTPSessionManager
, por lo que probablemente podría comenzar con el primero, que tiene la propiedad operationQueue
.
Gracias Sendoa por el enlace al problema de GitHub donde Mattt explica por qué esta funcionalidad ya no funciona. Hay una razón clara por la que esto no es posible con la nueva estructura NSURLSession
; Las tareas simplemente no son operaciones, por lo que la antigua forma de usar dependencias o lotes de operaciones no funcionará.
He creado esta solución utilizando un dispatch_group
que hace posible realizar solicitudes por lotes utilizando NSURLSession
, aquí está el código (pseudo):
// Create a dispatch group
dispatch_group_t group = dispatch_group_create();
for (int i = 0; i < 10; i++) {
// Enter the group for each request we create
dispatch_group_enter(group);
// Fire the request
[self GET:@"endpoint.json"
parameters:nil
success:^(NSURLSessionDataTask *task, id responseObject) {
// Leave the group as soon as the request succeeded
dispatch_group_leave(group);
}
failure:^(NSURLSessionDataTask *task, NSError *error) {
// Leave the group as soon as the request failed
dispatch_group_leave(group);
}];
}
// Here we wait for all the requests to finish
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
// Do whatever you need to do when all requests are finished
});
Quiero mirar, escribir algo que haga esto más fácil de hacer y discutir con Matt si esto es algo (cuando se implementa bien) que podría fusionarse en AFNetworking. En mi opinión, sería genial hacer algo como esto con la propia biblioteca. Pero tengo que verificar cuándo tengo algo de tiempo libre para eso.
Para request
que se pueden post
o get
, puede usar AFNetworking 2.0
para operaciones por lotes, ya que primero necesita crear una operación como esta:
//Request 1
NSString *strURL = [NSString stringWithFormat:@"your url here"];
NSLog(@"scheduleurl : %@",strURL);
NSDictionary *dictParameters = your parameters here
NSMutableURLRequest *request = [[AFHTTPRequestSerializer serializer] requestWithMethod:@"POST" URLString:strURL parameters:dictParameters error: nil];
AFHTTPRequestOperation *operationOne = [[AFHTTPRequestOperation alloc] initWithRequest:request];
operationOne = [AFHTTPResponseSerializer serializer];
[operationOne setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject)
{
//do something on completion
}
failure:^(AFHTTPRequestOperation *operation, NSError *error)
{
NSLog(@"%@",[error description]);
}];
//Request 2
NSString *strURL1 = [NSString stringWithFormat:@"your url here"];
NSLog(@"scheduleurl : %@",strURL);
NSDictionary *dictParameters1 = your parameters here
NSMutableURLRequest *request1 = [[AFHTTPRequestSerializer serializer] requestWithMethod:@"POST" URLString:strURL1 parameters:dictParameters1 error: nil];
AFHTTPRequestOperation *operationTwo = [[AFHTTPRequestOperation alloc] initWithRequest:request1];
operationTwo = [AFHTTPResponseSerializer serializer];
[operationTwo setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject)
{
//do something on completion
}
failure:^(AFHTTPRequestOperation *operation, NSError *error)
{
NSLog(@"%@",[error description]);
}];
//Request more here if any
Ahora realice la operación por lotes de esta manera:
//Batch operation
//Add all operation here
NSArray *operations = [AFURLConnectionOperation batchOfRequestOperations:@[operationOne,operationTwo] progressBlock:^(NSUInteger numberOfFinishedOperations, NSUInteger totalNumberOfOperations)
{
NSLog(@"%i of %i complete",numberOfFinishedOperations,totalNumberOfOperations);
//set progress here
yourProgressView.progress = (float)numberOfFinishedOperations/(float)totalNumberOfOperations;
} completionBlock:^(NSArray *operations)
{
NSLog(@"All operations in batch complete");
}];
[[NSOperationQueue mainQueue] addOperations:operations waitUntilFinished:NO];
Solo actualicé el hilo ... Tuve el mismo problema y después de algunas investigaciones encontré algunas buenas soluciones, pero decidí seguir con esta:
Estoy usando el proyecto llamado Bolts . Entonces, para la misma muestra publicada anteriormente por @ Mac_Cain13, sería:
[[BFTask taskWithResult:nil] continueWithBlock:^id(BFTask *task) {
BFTask *task = [BFTask taskWithResult:nil];
for (int i = 0; i < 10; i++) {
task = [task continueWithBlock:^id(BFTask *task) {
return [self executeEndPointAsync];
}];
}
return task;
}] continueWithBlock:^id(BFTask *task) {
// Everything was executed.
return nil;
}];;
- (BFTask *) executeEndPointAsync {
BFTaskCompletionSource *task = [BFTaskCompletionSource taskCompletionSource];
[self GET:@"endpoint.json" parameters:nil
success:^(NSURLSessionDataTask *task, id responseObject) {
[task setResult:responseObject];
}
failure:^(NSURLSessionDataTask *task, NSError *error) {
[task setError:error];
}];
}];
return task.task;
}
Básicamente, es apilar todas las tareas, esperar y desempaquetar hasta que no haya más tareas y, una vez completado todo, se ejecuta el último bloque de finalización.
Otro proyecto que hace lo mismo es RXPromise, pero para mí el código en Bolts fue más claro.