dispatch_async并在原始队列上调用完成处理程序

rma*_*ddy 24 objective-c grand-central-dispatch ios

我已经看到了一些相关问题,但似乎没有人回答这个问题.我想写一个在后台做一些工作的方法.我需要这个方法在用于原始方法调用的同一个线程/队列上调用完成回调.

- (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);
        });
    });
Run Code Online (Sandbox Code Playgroud)

这里需要什么神奇的咒语才能在与调用相同的队列或线程上调用完成处理程序sameMethod?我不想假设主线程.当然dispatch_get_current_queue不会被使用.

D.C*_*.C. 12

如果查看Apple文档,似乎有两种模式.

如果假定要在主线程上运行完成处理程序,则不需要提供队列.一个例子是UIViewanimations方法:

+ (void)animateWithDuration:(NSTimeInterval)duration animations:(void (^)(void))animations completion:(void (^)(BOOL finished))completion
Run Code Online (Sandbox Code Playgroud)

否则,API通常会要求调用者提供队列:

[foo doSomethingWithCompletion:completion targetQueue:yourQueue];
Run Code Online (Sandbox Code Playgroud)

我的建议是遵循这种模式.如果不清楚应该调用完成处理程序的队列,则调用者应该明确地将其作为参数提供.


Jos*_*ell 5

你不能真正使用队列,因为除了主队列之外,它们都不能保证在任何特定线程上运行.相反,您必须直接获取线程并执行块.

适应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
Run Code Online (Sandbox Code Playgroud)
- (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];
        }
        });
    });
Run Code Online (Sandbox Code Playgroud)

虽然你没有使用dispatch_async(),但是对于你的程序的其余部分,它仍然是异步的,因为它包含在原始的调度任务块中,并且waitUntilDone:NO使其与之异步.

  • 当然,@ BlackRider."NSOperationQueue"也有自己的私有线程,我很确定它是建立在GCD/libdispatch之上的. (3认同)