39

実行に時間がかかる完了ブロックを含む複数の操作(AFNetworkingリクエスト)と、すべてのリクエストの最後に保存する必要のあるCoreDataオブジェクトがあります。

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];

もちろん、リクエストは非同期であるため、これは私が望むようには機能しません。次のようにNSOperationQueueを追加してみました。

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];

これは少し良く見えます。を使用するwaitUntilAllOperationsAreFinishedと、キューはリクエストが終了するまで現在のスレッドをブロックしますが、成功ブロックが終了するまではブロックしません。これが本当に必要なことです。

これを良い方法で達成する方法についてのアイデアはありますか?

4

4 に答える 4

84

ディスパッチグループを使用します。

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];
于 2012-05-17T22:20:07.440 に答える
15

AFNetworkingは、GCDから抽象化したこの種の操作のメソッドを設計しました。

-enqueueBatchOfHTTPRequestOperationsWithRequests:progressBlock:completionBlock:

-enqueueBatchOfHTTPRequestOperations:progressBlock:completionBlock:

FAQをご覧ください

于 2012-08-09T14:44:34.867 に答える
1

私はこのようなものを信じています:

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];

ドキュメントを参照する: http://cocoadocs.org/docsets/AFNetworking/2.5.0/

于 2015-01-20T10:47:48.950 に答える
1

私の要件は、文字列(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)
    })

}

明らかに、この方法では、N個の非同期呼び出しではなく、カスケードで呼び出しが行われます。

于 2015-06-23T13:28:11.383 に答える