ios dispatch_async 并在原始队列上调用完成处理程序
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/13098030/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
dispatch_async and calling a completion handler on the original queue
提问by rmaddy
I've seen some related questions but none seem to answer this case. I want to write a method that will do some work in the background. I need this method to call a completion callback on the same thread / queue used for the original method call.
我看过一些相关的问题,但似乎没有人回答这种情况。我想编写一个可以在后台做一些工作的方法。我需要此方法在用于原始方法调用的同一线程/队列上调用完成回调。
- (void)someMethod:(void (^)(BOOL result))completionHandler {
dispatch_queue_t current_queue = // ???
// some setup code here
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
BOOL ok = // some result
// do some long running processing here
dispatch_async(current_queue, ^{
completionHandler(ok);
});
});
What magic incantation is needed here so the completion handler is called on the same queue or thread as the call to sameMethod
? I don't want to assume the main thread. And of course dispatch_get_current_queue
is not to be used.
这里需要什么魔法咒语才能在与调用相同的队列或线程上调用完成处理程序sameMethod
?我不想假设主线程。当然dispatch_get_current_queue
不能使用。
回答by D.C.
If you look through the Apple docs, there appear to be two patterns.
如果您查看 Apple 文档,似乎有两种模式。
If it is assumed that the completion handler is to be run on the main thread, then no queue needs to be provided. An example would be UIView
's animations
methods:
如果假设完成处理程序将在主线程上运行,则不需要提供队列。一个例子是UIView
的animations
方法:
+ (void)animateWithDuration:(NSTimeInterval)duration animations:(void (^)(void))animations completion:(void (^)(BOOL finished))completion
Otherwise, the API usually asks the caller to provide a queue:
否则,API 通常会要求调用者提供一个队列:
[foo doSomethingWithCompletion:completion targetQueue:yourQueue];
My suggestion is to follow this pattern. If it is unclear which queue the completion handler should be called, the caller should supply it explicitly as a parameter.
我的建议是遵循这种模式。如果不清楚应调用完成处理程序的哪个队列,调用者应将其作为参数显式提供。
回答by jscs
You can't really use queues for this because, aside from the main queue, none of them are guaranteed to be running on any particular thread. Instead, you will have to get the thread and execute your block directly there.
您不能真正为此使用队列,因为除了主队列之外,它们都不能保证在任何特定线程上运行。相反,您必须获取线程并直接在那里执行您的块。
Adapting from Mike Ash's Block Additions:
改编自Mike Ash 的 Block Additions:
// The last public superclass of Blocks is NSObject
@implementation NSObject (rmaddy_CompletionHandler)
- (void)rmaddy_callBlockWithBOOL: (NSNumber *)b
{
BOOL ok = [b boolValue];
void (^completionHandler)(BOOL result) = (id)self;
completionHandler(ok);
}
@end
- (void)someMethod:(void (^)(BOOL result))completionHandler {
NSThread * origThread = [NSThread currentThread];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
BOOL ok = // some result
// do some long running processing here
// Check that there was not a nil handler passed.
if( completionHandler ){
// This assumes ARC. If no ARC, copy and autorelease the Block.
[completionHandler performSelector:@selector(rmaddy_callBlockWithBOOL:)
onThread:origThread
withObject:@(ok) // or [NSNumber numberWithBool:ok]
waitUntilDone:NO];
}
});
});
Although you're not using dispatch_async()
, this is still asynchronous with respect to the rest of your program, because it's contained within the original dispatched task block, and waitUntilDone:NO
also makes it asynchronous with respect to that.
尽管您没有使用dispatch_async()
,但这对于程序的其余部分仍然是异步的,因为它包含在原始分派任务块中,并且waitUntilDone:NO
还使其异步。
回答by Arian Sharifian
not sure if this will solve the problem, but how about using NSOperations instead of GCD?:
不确定这是否能解决问题,但是如何使用 NSOperations 而不是 GCD?:
- (void)someMethod:(void (^)(BOOL result))completionHandler {
NSOperationQueue *current_queue = [NSOperationQueue currentQueue];
// some setup code here
NSOperationQueue *q = [[NSOperationQueue alloc] init];
[q addOperationWithBlock:^{
BOOL ok = YES;// some result
// do some long running processing here
[current_queue addOperationWithBlock:^{
completionHandler(ok);
}];
}];
回答by Loozie
I wanted to do some tasks on some queue and then execute a completion block as @rmaddy mentioned. I came across the Concurrency Programming Guide from Apple and implemented this (with dispatch_retain & dispatch_released commented out because I am using ARC) -- https://developer.apple.com/library/ios/documentation/General/Conceptual/ConcurrencyProgrammingGuide/OperationQueues/OperationQueues.html#//apple_ref/doc/uid/TP40008091-CH102-SW1
我想在某个队列上做一些任务,然后像@rmaddy 提到的那样执行一个完成块。我遇到了 Apple 的并发编程指南并实现了这个(dispatch_retain 和 dispatch_released 被注释掉了,因为我使用的是 ARC)——https: //developer.apple.com/library/ios/documentation/General/Conceptual/ConcurrencyProgrammingGuide/OperationQueues /OperationQueues.html#//apple_ref/doc/uid/TP40008091-CH102-SW1
void average_async(int *data, size_t len, dispatch_queue_t queue, void (^block)(int))
{
// Retain the queue provided by the user to make
// sure it does not disappear before the completion
// block can be called.
//dispatch_retain(queue); // comment out if use ARC
// Do the work on user-provided queue
dispatch_async(queue, ^{
int avg = average(data, len);
dispatch_async(queue, ^{ block(avg);});
// Release the user-provided queue when done
//dispatch_release(queue); // comment out if use ARC
});
}