2012-05-17 2 views
39

Ho più operazioni (sono richieste AFNetworking) con blocchi di completamento che richiedono del tempo per l'esecuzione e un oggetto Dati di base che deve essere salvato alla fine di tutte le richieste.Attendi fino a quando sono state eseguite più richieste di rete, compresi i blocchi di completamento

MyCoreDataObject *coreDataObject; 

AFHTTPRequestOperation *operation1 = [[AFHTTPRequestOperation alloc] initWithRequest:request1]; 
[operation1 setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) { 
    coreDataObject.attribute1 = responseObject; 
    sleep(5); 
}]; 
[operation1 start]; 

AFHTTPRequestOperation *operation2 = [[AFHTTPRequestOperation alloc] initWithRequest:request1]; 
[operation2 setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) { 
    coreDataObject.attribute2 = responseObject; 
    sleep(10); 
}]; 
[operation1 operation2]; 

[context save:nil]; 

Naturalmente, questo non funziona come voglio perché le richieste sono asincrone. Ho provato ad aggiungere un NSOperationQueue in questo modo:

NSOperationQueue *operationQueue = [[NSOperationQueue alloc] init]; 
[operationQueue setMaxConcurrentOperationCount:2]; 

AFHTTPRequestOperation *operation1 = [[AFHTTPRequestOperation alloc] initWithRequest:request1]; 
[operation1 setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) { 
    coreDataObject.attribute1 = responseObject; 
    sleep(5); 
}]; 
[operationQueue addOperation:operation1]; 

AFHTTPRequestOperation *operation2 = [[AFHTTPRequestOperation alloc] initWithRequest:request1]; 
[operation2 setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) { 
    coreDataObject.attribute2 = responseObject; 
    sleep(10); 
}]; 
[operationQueue addOperation:operation2]; 

[imageQueue waitUntilAllOperationsAreFinished]; 
[context save:nil]; 

Questo sembra un po 'meglio. Usando waitUntilAllOperationsAreFinished, la mia coda blocca il thread corrente fino a quando le mie richieste sono finite, ma non prima che i miei Blocchi di successo siano finiti, il che è proprio ciò di cui ho bisogno.

Qualche idea su come ottenere questo risultato in modo corretto?

risposta

84

Utilizzare i gruppi di spedizione.

dispatch_group_t group = dispatch_group_create(); 

MyCoreDataObject *coreDataObject; 

dispatch_group_enter(group); 
AFHTTPRequestOperation *operation1 = [[AFHTTPRequestOperation alloc] initWithRequest:request1]; 
[operation1 setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) { 
    coreDataObject.attribute1 = responseObject; 
    sleep(5); 
    dispatch_group_leave(group); 
}]; 
[operation1 start]; 

dispatch_group_enter(group); 
AFHTTPRequestOperation *operation2 = [[AFHTTPRequestOperation alloc] initWithRequest:request1]; 
[operation2 setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) { 
    coreDataObject.attribute2 = responseObject; 
    sleep(10); 
    dispatch_group_leave(group); 
}]; 
[operation2 start]; 

dispatch_group_wait(group, DISPATCH_TIME_FOREVER); 
dispatch_release(group); 

[context save:nil]; 
+1

grazie, questo funziona bene. Sono anche interessato se/come questo possa essere raggiunto senza bloccare il thread. qualche idea per questo? – choise

+22

Ehm, cosa intendi con "** aspetta ** fino a quando non vengono eseguite più operazioni" se non blocchi il thread? Ad ogni modo, se vuoi eseguire un blocco solo dopo aver eseguito tutti i blocchi di completamento, puoi usare 'dispatch_group_notify (group, queue,^{...});' invece di 'dispatch_group_wait()'. –

+1

cool! grazie! – choise

15

AFNetworking è metodo progettato per questo tipo di operazioni, che astrae dal GCD:

-enqueueBatchOfHTTPRequestOperationsWithRequests:progressBlock:completionBlock:

-enqueueBatchOfHTTPRequestOperations:progressBlock:completionBlock:

Date un'occhiata a FAQ

1

I belive qualcosa di simile :

NSMutableArray *mutableOperations = [NSMutableArray array]; 
for (NSURL *fileURL in filesToUpload) { 
    NSURLRequest *request = [[AFHTTPRequestSerializer serializer] multipartFormRequestWithMethod:@"POST" URLString:@"http://example.com/upload" parameters:nil constructingBodyWithBlock:^(id<AFMultipartFormData> formData) { 
     [formData appendPartWithFileURL:fileURL name:@"images[]" error:nil]; 
    }]; 

    AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request]; 

    [mutableOperations addObject:operation]; 
} 

NSArray *operations = [AFURLConnectionOperation batchOfRequestOperations:@[...] progressBlock:^(NSUInteger numberOfFinishedOperations, NSUInteger totalNumberOfOperations) { 
    NSLog(@"%lu of %lu complete", numberOfFinishedOperations, totalNumberOfOperations); 
} completionBlock:^(NSArray *operations) { 
    NSLog(@"All operations in batch complete"); 
}]; 
[[NSOperationQueue mainQueue] addOperations:operations waitUntilFinished:NO]; 

riferendosi ai documenti: http://cocoadocs.org/docsets/AFNetworking/2.5.0/

1

mie esigenze erano quelle di fare molte richiesta da un array di String (URL)

func updateSourceData(element: Int) { 

    if element > availableUrls.count - 1 { 
     return 
    } 

    let service = SourceDataServiceDao() 
    let currentUrl = availableUrls[element] 
    service.fooCall(url: currentUrl, completion: { (response, error) -> Void in 
     self.updateSourceData(element + 1) 
    }) 

} 

Ovviamente, in questo modo le chiamate sono effettuate in cascata, non N chiamate asincrone.