Является ли вызов - [NSRunLoop runUntilDate:] хорошей идеей? - PullRequest
9 голосов
/ 07 февраля 2011

Это вообще хорошая идея, чтобы позвонить -[NSRunLoop runUntilDate:]?Кажется, он работает без каких-либо проблем, но меня нервирует, что цикл выполнения запускается из цикла выполнения.

Дополнительная информация:

У меня есть проект, который сейчас загружаетсяданные из службы REST.Одним из важнейших элементов информации, который необходимо получить, является диапазон дат с действительными данными.Это очень маленький объем данных, который нужно получить только один раз, поэтому я решил, что лучший способ обработать его - это загрузить свойство, если локальная переменная nil.Я использую ASIHTTPRequest и ASINetworkQueue, поэтому по умолчанию все является асинхронным, и для того, чтобы это работало, это свойство не может возвращаться, пока данные не будут загружены и обработаны.Вот схема моего кода, имена переменных были изменены, чтобы защитить невинных:

__block BOOL isWorking = YES;
__block ASIHTTPRequest *request = [[[ASIHTTPRequest alloc] initWithURL:/*actual URL*/] autorelease];
[request setCompletionBlock:^{
    // set local variable
    isWorking = NO;
}];
[request setFailedBlock:^{
    // show alert to user
    isWorking = NO;
}];
[queue addOperation:request];

while (isWorking) {
    [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];
}

Опять же, это работает нормально.Есть ли потенциальные проблемы с использованием этого подхода?

Ответы [ 2 ]

4 голосов
/ 07 февраля 2011

Не лучше ли отобразить какой-нибудь счетчик и разорвать его в ответ на события асинхронного завершения из сетевого кода? Как:

[self displayLoadingSpinner];
[request setCompletionBlock:^{
    [self handleSuccess];
    dispatch_async(dispatch_get_main_queue(), ^{
        [self hideLoadingSpinner];
    }];
}];
[request setFailedBlock:^{
    [self handleFailure];
    dispatch_async(dispatch_get_main_queue(), ^{
        [self hideLoadingSpinner];
    }];
}];
[queue addOperation:request];

Я бы посчитал это лучше, чем обезьяна с помощью цикла выполнения. Но может быть, вы уже знаете это и просто хотите узнать, какие именно недостатки существуют в решении runloop?


Если вы хотите заблокировать, пока значение не будет готово, вы можете использовать семафор:

dispatch_semaphore_t sem = dispatch_semaphore_create(0);
[request setCompletionBlock:^{
    dispatch_semaphore_signal(sem);
}];
[queue addOperation:request];

dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
dispatch_release(sem);
3 голосов
/ 07 февраля 2011

Вы должны убедиться, что не делаете этого из любого метода, который может быть вызван циклом выполнения, который вы вызываете, если только перекрывающееся дерево вызовов не является полностью реентерабельным.

Код пользовательского интерфейса Cocoa Touch не задокументирован как повторно входящий (фактически, есть предупреждения / подсказки от Apple DTS, что это не так), поэтому, если ваш обработчик данных выборки может быть вызван каким-либо образомМетод пользовательского интерфейса (или другой непереходный код, который можно вызывать в цикле выполнения пользовательского интерфейса), вызывать цикл выполнения пользовательского интерфейса изнутри не рекомендуется.

...