iOS-管理和跟踪多个并发任务

标签 ios objective-c multithreading cocoa-touch grand-central-dispatch

在我的应用中,我需要从多个来源加载数据并将它们放在一个 TableView 中。一个接一个地收集每一个来源将花费很长时间。为了解决这个问题,我需要同时运行所有下载操作。由于是下载任务,理论上直接运行即可,但问题是线程上只有部分代码是异步运行的,需要主线程才能完成。

所以为了让所有这些都在后台运行,我需要使用 GCD,我对它的经验不多。

//DataLoader.m

dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void){
    [self.webLoader getFeedWithCompletion:self.thatOtherCompletionBlock];
    [self.otherDataLoader getDataWithCompletion:self.completionBlock];
    [self.thatDataLoader getThatDataWithCompletion:self.anotherCompletionBlock]
    dispatch_async(dispatch_get_main_queue(), ^(void){

    });
});

但是,由于部分任务已经是异步的,我需要弄清楚将 GCD 代码放在哪里。

我可以把它放在开始任务之前,就像我在上面所做的那样。然而,这可能有效,因为任务已经部分在后台运行(在某些情况下我无法更改),在后台运行已经部分在后台运行的任务似乎很浪费。为什么要在另一个线程中运行已经在后台线程中运行的东西?

另一种选择是在获取提要的实际类中使用 GCD(例如 webloader),将其放在所有未在后台运行的代码上

- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
    dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void){
    .......

 });

哪种方式更好?

还有一个问题。由于部分任务是异步的,因此它们使用完成 block 。我不仅需要在后台运行完成 block ,我还需要弄清楚哪一个是最后一个完成的,这样我就可以运行一些代码来清理并整齐地打包数据并将其发送到 View Controller 。

我想到的方法是为每个任务使用一个 BOOL,只需在完成时将其更改为 true 即可。然后在我的完成 block 中,我可以检查所有其他任务是否已完成,如果是,则运行清理代码。然而,这可能不是最优雅的解决方案。

处理这些任务的最佳方式是什么,以确保这一切都在后台进行?

最佳答案

GCD 组可以很容易地用于此目的。组允许您跟踪组的任意“成员”,并挂接一个 block 以在组的所有成员都完成时运行。这很方便。例如(使用您的代码):

dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void){
    dispatch_group_t group = dispatch_group_create();

    dispatch_group_enter(group); // + 1
    [self.webLoader getFeedWithCompletion: ^{
        self.thatOtherCompletionBlock();
        dispatch_group_leave(group); // - 1
    }];

    dispatch_group_enter(group); // + 1
    [self.otherDataLoader getDataWithCompletion:^{
        self.completionBlock();
        dispatch_group_leave(group); // - 1
    }];

    dispatch_group_enter(group); // + 1
    [self.thatDataLoader getThatDataWithCompletion:^{
        self.anotherCompletionBlock();
        dispatch_group_leave(group); // - 1
    }];

    dispatch_group_notify(group, dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        // This will get executed once all three of the prior completion blocks have been run.
        // i.e. when the group "count" goes to zero.
    });

    dispatch_release(group);
});

您也可以使用 NSOperation 的操作间依赖特性来实现这一点,尽管有点迂回。像这样:

NSOperationQueue* q = [[[NSOperationQueue alloc] init] autorelease];

NSOperation* completionA = [NSBlockOperation blockOperationWithBlock: self.thatOtherCompletionBlock];
NSOperation* completionB = [NSBlockOperation blockOperationWithBlock: self.completionBlock];
NSOperation* completionC = [NSBlockOperation blockOperationWithBlock: self.anotherCompletionBlock];

NSBlockOperation* afterAllThree = [[[NSBlockOperation alloc] init] autorelease];
[afterAllThree addDependency: completionA];
[afterAllThree addDependency: completionB];
[afterAllThree addDependency: completionC];
[afterAllThree addExecutionBlock:^{
    // This will get executed once all three of the prior completion blocks have been run.
}];

// Kick off the tasks
[q addOperationWithBlock:^{
    [self.webLoader getFeedWithCompletion: ^{ [q addOperation: completionA];}];
    [self.otherDataLoader getDataWithCompletion:^{ [q addOperation: completionB]; }];
    [self.thatDataLoader getThatDataWithCompletion:^{ [q addOperation: completionC]; }];
}];

我个人更喜欢 dispatch_group 方法,但它们都可以完成工作。

关于iOS-管理和跟踪多个并发任务,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18261340/

相关文章:

ios - UIImagePickerController 照片预览被未知黑框遮挡

iOS 多 Collection View

ios - 在全局队列中停止 NSRunLoop

multithreading - 在Scheme (Bigloo) 中正确使用线程

python - 多线程不同的脚本

C++ 多线程,在并行多个线程时出现段错误

ios - 如何使用照片位置数据

iOS 13 将圆形按钮更改为对角线按钮

ios - 隐藏没有空格的 View

ios - JSON 和 Xcode 6 UITableView