GCD и выполните образцы SelectInBackground ниже. Но сначала давайте посмотрим на ваш код.
Вы не можете ждать, где вы хотите в коде выше.
Вот код, который вы имели. Где вы говорите, ждать в комментарии неверно. Смотрите, где я добавил NO.
- (void) solvePuzzle:(id)sender{
solveButton.enabled = NO;
solveButton.title = @"Working . . . .";
// I've tried using this as a Background thread, but I can't get the code to waitTilDone before continuing and changing the button state.
[self performSelectorInBackground:@selector(createTreeFromNode:) withObject:rootNode];
// NO - do not wait or enable here.
// Need to wait here until createTreeFromNode is finished.
solveButton.enabled=YES;
}
Цикл сообщений пользовательского интерфейса работает в основном потоке, который поддерживает работу пользовательского интерфейса. Функция executePuzzle вызывается в главном потоке, поэтому вы не можете ждать - он заблокирует пользовательский интерфейс. Он также не может вернуть кнопку в положение «включено» - работа еще не выполнена.
Работа рабочей функции в фоновом потоке заключается в выполнении работы, а затем, когда это делается, для обновления пользовательского интерфейса. Но вы не можете обновить пользовательский интерфейс из фонового потока. Если вы не используете блоки и используете executeSelectInBackground, то когда вы закончите, вызовите executeSelectorOnMainThread, который вызывает селектор для обновления вашего пользовательского интерфейса.
executeSelectorInBackground Пример:
В этом фрагменте у меня есть кнопка, которая вызывает долгосрочную работу, метка состояния, и я добавил ползунок, чтобы показать, что я могу переместить ползунок, пока работа bg завершена.
// on click of button
- (IBAction)doWork:(id)sender
{
[[self feedbackLabel] setText:@"Working ..."];
[[self doWorkButton] setEnabled:NO];
[self performSelectorInBackground:@selector(performLongRunningWork:) withObject:nil];
}
- (void)performLongRunningWork:(id)obj
{
// simulate 5 seconds of work
// I added a slider to the form - I can slide it back and forth during the 5 sec.
sleep(5);
[self performSelectorOnMainThread:@selector(workDone:) withObject:nil waitUntilDone:YES];
}
- (void)workDone:(id)obj
{
[[self feedbackLabel] setText:@"Done ..."];
[[self doWorkButton] setEnabled:YES];
}
Образец GCD:
// on click of button
- (IBAction)doWork:(id)sender
{
[[self feedbackLabel] setText:@"Working ..."];
[[self doWorkButton] setEnabled:NO];
// async queue for bg work
// main queue for updating ui on main thread
dispatch_queue_t queue = dispatch_queue_create("com.sample", 0);
dispatch_queue_t main = dispatch_get_main_queue();
// do the long running work in bg async queue
// within that, call to update UI on main thread.
dispatch_async(queue,
^{
[self performLongRunningWork];
dispatch_async(main, ^{ [self workDone]; });
});
}
- (void)performLongRunningWork
{
// simulate 5 seconds of work
// I added a slider to the form - I can slide it back and forth during the 5 sec.
sleep(5);
}
- (void)workDone
{
[[self feedbackLabel] setText:@"Done ..."];
[[self doWorkButton] setEnabled:YES];
}