如何在同步运行时超时异步方法

时间:2013-07-19 16:54:00

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

这基本上是我正在做的同步运行异步方法:

这实际上在调用一次时起作用,但是当多次调用时,它最终将保持在while循环内并且永远不会发出信号。有关如何设置计时器以在一段时间后最终超时的任何想法?

__block SomeClass *result = nil;

dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0UL);
dispatch_async(queue, ^{
    [[SomeManager sharedInstance] someMethodWithCallback:^(id responseObject, NSError *error) {
        if (!error) {
            result = (SomeClass *)ResponseObject;
        }

        dispatch_semaphore_signal(semaphore);
    }];
});

// wait with a time limit
while (dispatch_semaphore_wait(semaphore, DISPATCH_TIME_NOW)) {
    [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0]];
}

dispatch_release(semaphore);

由于

3 个答案:

答案 0 :(得分:1)

这看起来有点像GCD虐待我。 ;)您是否正在运行运行循环,因为这是在主线程上执行的?为什么不直接使用完成处理程序中的dispatch_async()来调用主线程上的处理程序?例如:

- (void)handleDataReady: (id) results error: (NSError *) error {
    // update your app
}

- (void)performAsyncUpdate {
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0UL);
    dispatch_async(queue, ^{
        [[SomeManager sharedInstance] someMethodWithCallback:^(id responseObject, NSError *error) {
            dispatch_async(dispatch_get_main_queue(), ^{
                [self handleDataReady:responseObject error:error];
        }];
    });
}

答案 1 :(得分:1)

如果你真的想让它同步,即在操作完成之前阻塞调用线程,那么使用以下模式(当然你想避免阻塞线程,如果可能的话)

NSCondition *waitCondtion = [NSCondition new];
__block BOOL completed = NO;

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0UL);
dispatch_async(queue, ^{
    [[SomeManager sharedInstance] someMethodWithCallback:^(id responseObject, NSError     *error) {
        if (!error) {
            result = (SomeClass *)ResponseObject;
        }

       [waitCondtion lock];
       completed = YES;
       [waitCondition signal];
       [waitCondition unlock];
    }];
});

[waitCondtion lock];
if (!completed)
    [waitCondtion wait];
[waitCondition unlock];

你也可以使用“waitUntilDate:”来延迟一段时间后的等待。

但是,只有“someMethodWithCallback不会在被阻塞的同一个线程上调用其回调块时,此模式才有效。我复制了您的代码,因为实现”someMethodWithCallback“的方式并不明显。正在使用异步模式,那么它必须异步执行某些操作,因此为什么要在dispatch_async中调用它?它会在什么线程上调用它的回调块?

答案 2 :(得分:0)

你应该用完成处理程序完成时处理结果所需的任何代码“填充”完成处理程序(并完全删除该运行循环)。

为了“中止”异步操作,您应该提供发送异步结果提供程序的cancel消息。

在您的情况下,由于您有一个单身人士,cancel消息必须像这样发送:

 [[SomeManager sharedInstance] cancel];

当操作收到cancel消息时,它应该尽快中止其任务并使用适当的NSError对象调用完成处理程序,指示它已被取消。

注意,取消消息可能是异步 - 这意味着,当它返回时,接收方仍然可以执行任务。

您可以通过设置定时器来实现“超时”,定时器会将取消消息发送给操作,除非在操作完成时它已失效。