У меня есть IBAction с простым кодом внутри:
-(IBAction)change:(id)sender {
[textfield setHidden:NO];
[self dolengthyaction];
}
'textfield' - это NSTextField в файле пера, а -'dolengthyaction' - это функция, выполнение которой занимает около минуты.
Мой вопрос: почему текстовое поле не отображается до тех пор, пока ПОСЛЕ выполнения "dolongyaction" не будет выполнено? Я хочу, чтобы это было раскрыто до того, как начнется долговременное действие. Это врожденная проблема или что-то не так с моим кодом? (или в другой части моего кода?)
Я все еще не очень хорош в программировании, поэтому прошу прощения, если я что-то плохо сформулировал и что-то неправильно отформатировал.
РЕДАКТИРОВАТЬ: кроме этого IBAction и -dolengthyaction больше ничего нет...
-(void)doLengthyAction {
sleep(10);
}
-(IBAction)change:(id)sender {
[textfield setHidden:NO];
[self doLengthyAction];
[textfield setHidden:YES];
}
Все, что я действительно хочу сделать, это отобразить метку, когда действие выполняется, и скрыть его, когда оно будет выполнено.
По сути, это означает, что сейчас он вообще не отображается.
На самом деле в -doLengthyAction это не sleep(10), а скорее операция NSFileManager, которая копирует около 50 Мб материала. Код был довольно длинным, но если вы хотите, чтобы я его опубликовал, я могу. Я тестировал его с помощью sleep(), но он тоже не работает.
Ответ 1 · рейтинг 6 · drawnonward
Все операции рисования (включая скрытие и отображение видов) запускаются из цикла выполнения. Цикл выполнения не может выполнить следующее событие до тех пор, пока ваша функция не вернется.
Если у вас есть операция, выполнение которой занимает больше секунды, вы должны выполнять ее в потоке. После его завершения используйте PerformSelectorOnMainThread, чтобы внести изменения в пользовательский интерфейс в основном потоке.
Ответ 2 · рейтинг 5 · wbyoung
Как упоминалось в некоторых из предыдущих ответов, приложение должно вернуться в основной цикл выполнения, прежде чем оно будет перерисовываться (это оптимизация, позволяющая избежать перерисовки при внесении большого количества изменений).
Вы действительно должны обрабатывать вещи в фоновом потоке, если они собираются работать в течение длительного времени. Если вы этого не сделаете, пользовательский интерфейс будет играть в пляжный мяч, пока ваша операция выполняется.
Если вы нацелены на 10.6+, вы можете использовать GCD и блоки следующим образом, чтобы легко запускать вещи в фоновом режиме (и вам не нужно определять несколько методов для выполнения задач):
-(void)doLengthyAction {
sleep(10);
}
-(IBAction)change:(id)sender {
[textfield setHidden:NO];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[self doLengthyAction];
dispatch_async(dispatch_get_main_queue(), ^{
[textfield setHidden:YES];
});
});
}
Конечно, используя это, вам нужно убедиться, что то, что происходит в длительном действии, является потокобезопасным, но в конечном итоге вы получите лучший пользовательский опыт. Для получения дополнительной информации об этом типе кода CGD вы можете захотеть прочитать это.