iOS多线程确保异步块返回数据

时间:2016-10-20 15:59:09

标签: ios objective-c multithreading httprequest

我正在尝试使用多线程来实现一系列的http请求,首先我想将几张照片上传到第三方api,并希望所有返回的响应全部收集,然后发出最终的http请求。但是我用以下代码做的事情无法让它发挥作用。

//With valid token, I can upload to a third-party server a list of Photos
//after I have each of the photo uploaded, a "key" is responsed, denoting the name of the Photo
//I would like to collect all the "key", and post to my own server to record them in database

- (void)uploadMultiplePhotoAssets:(NSArray *)assets Token:(NSString *)token
{
    dispatch_group_t group = dispatch_group_create();

    //I would like to use these arrays to store the result of the following request in each dispatch
    __block NSMutableArray *successUploadedImageKeys = [NSMutableArray array];
    __block NSMutableArray *failedAssetIndex = [NSMutableArray array];

    for(int i= 0; i < assets.count; i++)
    {
        dispatch_group_async(group,dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^ {

            [ThirdPartyApi uploadPHAsset:assets[i] Token:token complete:^(NSString *key) {

                if(key)
                {   //if key is not nil, the request is successful
                    NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
                    [dict setObject:key forKey:@"key"];
                    [dict setObject:@(i) forKey:@"index"];
                    [successUploadedImageKeys addObject:[dict copy]];
                }
                else
                {   
                    //if request failed, record which one failed
                    [failedAssetIndex addObject:@(i)];
                }
            }];
        });
    }

    //I would like to handle all the result after each thread is performed, and all the "complete" blocks are also finished
    dispatch_group_notify(group,dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^ {

        NSLog(@"successUploadedImageKeys is %@, failedAssetIndex is %@", successUploadedImageKeys, failedAssetIndex);

        [MyApi postToMyBackend:successUploadedImageKeys]; 

    });
}

如果我使用NSOperation,它也是相同的,在最终的http请求被触发之前不会等待所有complete块。

在C中,如果编写MPI,则有一种方法可以等待所有线程处于相同状态。在Obj-C中实现这一目的是什么?我如何等待异步响应到达,然后一起做所有响应?

1 个答案:

答案 0 :(得分:0)

好老完成处理程序怎么样? (如果需要,由读者决定将任何工作分配到后台线程)

-(void) uploadAsset: (id) asset successKeys: successUploadedImageKeys failedAssets: failedAssetIndex completionHandler: (void(^)(void)) completion {
    [ThirdPartyApi uploadPHAsset:assets[i] Token:token complete:^(NSString *key) {

        if(key)
        {   //if key is not nil, the request is successful
            NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
            [dict setObject:key forKey:@"key"];
            [dict setObject:@(i) forKey:@"index"];
            [successUploadedImageKeys addObject:[dict copy]];
        }
        else
        {
            //if request failed, record which one failed
            [failedAssetIndex addObject:@(i)];
        }
        completionHandler(completion);
    }];
}

-(void) uploadAssets: (NSMutableSet*) assets token:(NSString *)token successKeys: successUploadedImageKeys failedAssets: failedAssetIndex completionHandler: (void(^)(void)) completion {
    id nextAsset = assets.anyObject;
    [self uploadAsset: nextAsset successKeys:successUploadedImageKeys failedAssets:failedAssetIndex completionHandler:^{
        [assets removeObject:nextAsset];
        if (assets.count) {
            [self uploadAssets:assets token:token successKeys:successUploadedImageKeys failedAssets:failedAssetIndex completionHandler:completion];
        } else {
            completion();
        }

    }];
}

-(void) uploadMultiplePhotoAssets:(NSArray *)assets token:(NSString *)token {

    NSMutableArray *successUploadedImageKeys = [NSMutableArray array];
    NSMutableArray *failedAssetIndex = [NSMutableArray array];

    [self uploadAssets: [NSMutableSet setWithArray:assets] token:(NSString *)token successKeys: successUploadedImageKeys failedAssets: failedAssetIndex completionHandler: (void(^)(void)) {
        // done
        NSLog(@"successUploadedImageKeys is %@, failedAssetIndex is %@", successUploadedImageKeys, failedAssetIndex);
        [MyApi postToMyBackend:successUploadedImageKeys];
    }];
}