27

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

- (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);
        });
    });

这里需要什么魔法咒语,以便在与调用相同的队列或线程上调用完成处理程序sameMethod?我不想假设主线程。当然dispatch_get_current_queue是不能使用的。

4

4 回答 4

13

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

如果假设完成处理程序将在主线程上运行,则不需要提供队列。一个例子是UIView'sanimations方法:

+ (void)animateWithDuration:(NSTimeInterval)duration animations:(void (^)(void))animations completion:(void (^)(BOOL finished))completion

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

[foo doSomethingWithCompletion:completion targetQueue:yourQueue];

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

于 2012-10-27T08:37:38.110 回答
6

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

改编自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];
        }
        });
    });

尽管您没有使用dispatch_async(),但这对于您的程序的其余部分仍然是异步的,因为它包含在原始调度的任务块中,并且waitUntilDone:NO相对于它也使其异步。

于 2012-10-27T08:14:35.563 回答
3

不确定这是否能解决问题,但是使用 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);
    }];
}];
于 2013-05-07T20:04:26.817 回答
0

我想在某个队列上执行一些任务,然后像@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
});
}
于 2013-12-09T19:55:18.353 回答