大中央派遣筑巢

时间:2015-02-03 11:56:06

标签: ios objective-c grand-central-dispatch dispatch-async

我在调度异步块中编写了一段代码。如下所示:

dispatch_queue_t queue= dispatch_queue_create("action1", NULL);

dispatch_async(queue, ^{           
   [self method1];            
   [self method2];        
   [self method3];

   dispatch_async(dispatch_get_main_queue(), ^{
       //Update UI
   });       
});

现在,如果我想在主线程上执行method3怎么办?只需使用

- (void) method3
{
    dispatch_async(dispatch_get_main_queue(), ^{
        //Do method 3 on main thread
    });
}

这是正确的方法吗?我只想在我的UI更新之前先执行方法1 2和3,并且需要在主线程上执行method3。

2 个答案:

答案 0 :(得分:2)

是的,这很好。不可否认,让方法3向主队列调度一些东西感觉多余,只是让调用第三种方法的例程然后转向并将其他东西分派给主队列。这可能没什么问题(我可以构建一个场景,正确地做到这一点)。对主线程分派两次是否有意义完全取决于这两个块的执行情况,但没有一点上下文,感觉有点多余。

但是把它放在一边,创建队列的代码,向它发送代码,然后将最后一些代码发送回主线程,没有任何问题。这是一种非常常见的模式。

答案 1 :(得分:2)

有几件事需要考虑。首先,您应该努力不将主线程重新分发到主线程,因此您的-method3应该看起来像:

- (void)method3
{
    dispatch_block_t work = ^{
        // The actual work that method3 does
    };

    if ([NSThread isMainThread])
        work();
    else
        dispatch_async(dispatch_get_main_queue(), work);
}

我有几个"适配器"我有时会使用的功能。他们在这里:

// If we're already on a background thread, just do it now, otherwise dispatch_async
void ensure_bg_thread_trysync(dispatch_block_t block)
{
    if (![NSThread isMainThread])
    {
        block();
    }
    else
    {
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), block);
    }
}

// If we're already on the main thread, just do it now, otherwise dispatch_async
void ensure_main_thread_trysync(dispatch_block_t block)
{
    if ([NSThread isMainThread])
    {
        block();
    }
    else
    {
        dispatch_async(dispatch_get_main_queue(), block);
    }
}

对于一个接一个地链接你的操作,有很多选择。在Objective-C中,Continuation Passing Style有点笨重,但可以合理使用。这里的想法是你的方法返回void并取一个块参数"接下来要做什么。"因此,-method3适用于使用CPS的示例可能看起来像(为方便起见使用上述函数:

- (void)method3AndThen: (dispatch_block_t)continuation
{
    ensure_main_thread_trysync(^{
        // The actual work that method3 does
        // ...

        // Then call the next thing...
        if (continuation) continuation();
    };
}


dispatch_async(queue, ^{
    [self method1];
    [self method2];
    [self method3AndThen: ^{
        ensure_main_thread_trysync(^{
            // Update UI
        });
    }];
});

另一个选择,更多的Objective-C-ish将使用NSOperationQueueNSOperation,它们内置支持队列之间的依赖关系链接。您的示例可能使用NSOperation s:

NSOperation* op1 = [NSBlockOperation blockOperationWithBlock:^{ [self method1]; }];
NSOperation* op2 = [NSBlockOperation blockOperationWithBlock:^{ [self method2]; }];
NSOperation* op3 = [NSBlockOperation blockOperationWithBlock:^{ [self method3]; }];
NSOperation* updateUIOp = [NSBlockOperation blockOperationWithBlock:^{
    NSParameterAssert([NSThread isMainThread]);
    NSLog(@"Updating UI on Main Thread");
}];

[updateUIOp addDependency: op1];
[updateUIOp addDependency: op2];
[updateUIOp addDependency: op3];

NSOperationQueue* bgQueue = [NSOperationQueue new];
[bgQueue addOperation: op1]; // Background Thread
[bgQueue addOperation: op2]; // Background Thread

[[NSOperationQueue mainQueue] addOperation: op3]; // Main thread
[[NSOperationQueue mainQueue] addOperation: updateUIOp]; // Main thread

注意:此代码假定-method1-method2-method3可以相互并发执行。如果他们需要按顺序执行,您只需在它们之间添加依赖关系,如下所示:[op2 addDependency: op1]; [op3 addDependency: op2];

GCD是新的热点,因此它最近会有更多的播出时间,但是NSOperation / NSOperationQueue非常强大(更不用说它们已经在它们之上实现了) GCD)