2012-03-06 4 views
6

Я создаю приложение, которое извлекает набор результатов из базы данных. Я использую MBProgressHUD, чтобы показать ход запроса с помощью анимации. Метод, который я использую, вызывает анимацию при выполнении метода в другом потоке, и как только это будет сделано, он скрывает анимацию. Мой вопрос, после вызова:Многопоточность в iOS - как заставить поток ждать состояния?

[HUD showWhileExecuting:@selector(getResults) onTarget:self withObject:nil animated:YES]; 

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

[HUD showWhileExecuting:@selector(getResults) onTarget:self withObject:nil animated:YES]; 

if(self.thereAreEvents) { 
    [self performSegueWithIdentifier:@"searchResults" sender:self]; 
} else { 
    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"No results" message:@"Sorry, there are no results for your search. Please try again." delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil, nil]; 
    [alert show]; 
    [alert release]; 
} 

self.thereAreEvents получает набор в конце метода getResults. Однако, поскольку этот метод вызывается в другом потоке, эта строка выполнения продолжается и отображает предупреждение, даже если в базе данных есть события.

Итак, у меня есть два вопроса: что является самым простым способом реализации механизма ожидания сигнала в iOS и что является наиболее эффективным способом реализации такого механизма в iOS?

Спасибо!

ответ

2

Вы также можете рассмотреть NSConditionLock.

Так что это будет что-то вроде этого на нить 1:

[conditionLock lockWhenCondition:kConditionOkayToProceed]; 
[conditionLock unlockWithCondition:kConditionGettingResults]; 

[HUD show...] 

[conditionLock lockWhenCondition:kConditionResultsFetched]; 
[conditionLock unlockWithCondition:kConditionOkayToProceed]; 

И в HUD:

- (void)show... 
{ 
    [conditionLock lockWhenCondition:kConditionGettingResults]; 

    // stuff here 

    [conditionLock unlockWithCondition:kConditionResultsFetched]; 
} 

Хотя гораздо лучшим решением было бы передать блок или цель/селектор к HUD, который он должен выполнять при получении результатов.

EDIT: так что вы бы в конечном итоге с кодом, как:

[HUD showWhileExecuting:@selector(getResults) 
    onTarget:self 
    withObject:nil 
    animated:YES 
    performWhenFinished: 
    ^{ 
     if(self.thereAreEvents) { 
      [self performSegueWithIdentifier:@"searchResults" sender:self]; 
     } else { 
      UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"No results" message:@"Sorry, there are no results for your search. Please try again." delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil, nil]; 
      [alert show]; 
      [alert release]; 
     } 
     }]; 

И в HUD:

- (void)showWhile... performWhenFinished:(dispatch_block_t)block 
{ 
    // all the other stuff you were going to do here, then 
    // eventually... 

    // if no guarantees, maybe just: 
    block(); 

    // otherwise, if promised to dispatch to the main queue: 
    dispatch_async(dispatch_get_main_queue(), block); 
} 

С HUD имея дополнительный интеллект, чтобы взять dispatch_block_t в качестве последнего аргумента и называть его, когда результаты (независимо от того, гарантируют ли вы отправку в основной поток или иначе).

+0

Я вижу. Мне все еще нужно узнать о программировании для iOS! Я посмотрю на это. Благодаря! – KerrM

+0

Шаблон 'pass a block' относительно новый, но, похоже, направление Apple направлено на новые API в iOS 5. Проверьте, например. 'TWRequest' или' ACAccountStore'. На самом деле, вероятно, было бы лучше использовать 'completeHandler:', а не 'performWhenFinished:' для поставки блока, согласно соглашению, которое, кажется, появляется. – Tommy

0

Не уверен, что это лучший способ сделать это, но я бы попытался использовать цикл while, чтобы наблюдать некоторые логические значения с чем-то вроде [NSThread sleepForTimeInterval: 1]; внутри цикла.

Возможно также установить тайм-аут.

0

Это ваш путь: Concurrency Programming Guide

также: Synchronization

Чётко: Using Locks. Думаю, последняя могла бы помочь.

Еще один простой подход, это плохо, но работает

NSAssert(![NSThread isMainThread], @"Do not run on MAIN thread"); 
while (yourCondition) { [NSThread sleepForTimeInterval:0.2]; } 
11

Вы можете использовать плотный цикл ожидания для быстрого и грязного раствора:

__block BOOL finished = NO; 
dispatch_async(/* global queue */, ^{ 
    // … 
    finished = YES; 
}); 
while (!finished) /* waiting */; 

В «реальном» коде лучше использовать семафор:

Это лучше, чем цикл занятости, потому что заблокированная нить не потребляет процессорное время ,

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

+0

Спасибо за ответ. Честно говоря, я полностью потерял, когда дело доходит до программирования iOS, но я рассмотрю асинхронные обратные вызовы. Еще раз спасибо! – KerrM

+0

Просто комментарий, dispatch_release не требуется, так как iOS6 –

0

вы можете использовать dispatch_time_t, как ..

double delayInSeconds = 2.0; 
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC)); 
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){ 
    <#code to be executed on the main queue after delay#> 
}); 
Смежные вопросы