Как мне ждать завершения асинхронно отправленного блока? - PullRequest
176 голосов
/ 01 декабря 2010

Я тестирую некоторый код, который выполняет асинхронную обработку с использованием Grand Central Dispatch. Код тестирования выглядит следующим образом:

[object runSomeLongOperationAndDo:^{
    STAssert…
}];

Тесты должны ждать завершения операции. Мое текущее решение выглядит так:

__block BOOL finished = NO;
[object runSomeLongOperationAndDo:^{
    STAssert…
    finished = YES;
}];
while (!finished);

Что выглядит немного грубо, знаете ли вы лучший способ? Я мог бы выставить очередь и затем заблокировать, вызвав dispatch_sync:

[object runSomeLongOperationAndDo:^{
    STAssert…
}];
dispatch_sync(object.queue, ^{});

… но это может показаться слишком много на object.

Ответы [ 12 ]

0 голосов
/ 18 апреля 2014

Иногда также полезны циклы ожидания. Можете ли вы подождать, пока не получите некоторый (может быть BOOL) сигнал от асинхронного метода обратного вызова, но что, если ответа нет, и вы хотите выйти из этого цикла? Ниже приведено решение, в основном с ответом выше, но с добавлением Timeout.

#define CONNECTION_TIMEOUT_SECONDS      10.0
#define CONNECTION_CHECK_INTERVAL       1

NSTimer * timer;
BOOL timeout;

CCSensorRead * sensorRead ;

- (void)testSensorReadConnection
{
    [self startTimeoutTimer];

    dispatch_semaphore_t sema = dispatch_semaphore_create(0);

    while (dispatch_semaphore_wait(sema, DISPATCH_TIME_NOW)) {

        /* Either you get some signal from async callback or timeout, whichever occurs first will break the loop */
        if (sensorRead.isConnected || timeout)
            dispatch_semaphore_signal(sema);

        [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode
                                 beforeDate:[NSDate dateWithTimeIntervalSinceNow:CONNECTION_CHECK_INTERVAL]];

    };

    [self stopTimeoutTimer];

    if (timeout)
        NSLog(@"No Sensor device found in %f seconds", CONNECTION_TIMEOUT_SECONDS);

}

-(void) startTimeoutTimer {

    timeout = NO;

    [timer invalidate];
    timer = [NSTimer timerWithTimeInterval:CONNECTION_TIMEOUT_SECONDS target:self selector:@selector(connectionTimeout) userInfo:nil repeats:NO];
    [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];
}

-(void) stopTimeoutTimer {
    [timer invalidate];
    timer = nil;
}

-(void) connectionTimeout {
    timeout = YES;

    [self stopTimeoutTimer];
}
0 голосов
/ 27 января 2014
dispatch_semaphore_t sema = dispatch_semaphore_create(0);
[object blockToExecute:^{
    // ... your code to execute
    dispatch_semaphore_signal(sema);
}];

while (dispatch_semaphore_wait(semaphore, DISPATCH_TIME_NOW)) {
    [[NSRunLoop currentRunLoop]
        runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0]];
}

Это сделало это для меня.

...