我在调度异步块中编写了一段代码。如下所示:
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。
答案 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将使用NSOperationQueue
和NSOperation
,它们内置支持队列之间的依赖关系链接。您的示例可能使用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)