NSThread и UIViewController взаимодействие - PullRequest
5 голосов
/ 03 октября 2008

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

(а) не работает

-(void)myCallbackInThread
{
    // move on...
    UIApplication* app = [UIApplication sharedApplication];
    [app changeView];
}

тогда я обнаружил, что представление появляется, но не отвечает на ввод пользователя.

Если я изменю код следующим образом

(б) работает

-(void)myCallbackInThread
{
    // move on...
    UIApplication* app = [UIApplication sharedApplication];
    [app performSelectorOnMainThread:@selector(moveToMain) withObject:nil waitUntilDone:FALSE];
}

Тогда все работает просто отлично.

Есть намеки на то, почему?

Ответы [ 4 ]

2 голосов
/ 03 октября 2008

Как сказано в документации: «Если вы не уверены в конкретной графической операции, запланируйте ее выполнение из основного потока».

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

2 голосов
/ 08 ноября 2008

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

Основная причина того, что ваш второй пример работает, а не ваш первый, заключается в том, что UIApplication устанавливает и обрабатывает цикл выполнения и диспетчер событий для вас в главном потоке. Итак, когда вы вызываете executeSelectorInMainThread, селектор отправляется в основной цикл выполнения, который затем может обрабатывать ваш графический интерфейс и другие события. Диспетчер событий также запускается и управляется UIApplication в главном потоке.

В общем, не выполняйте никаких действий по управлению графическим интерфейсом во вторичном потоке. Отправьте их в основной поток. И если вам нужна обработка во вторичном потоке (для таких вещей, как таймеры или асинхронные вызовы и т. Д.), Вам нужно запустить и управлять собственным циклом выполнения в этом потоке (см. NSRunLoop для получения дополнительной информации об управлении цикл выполнения).

2 голосов
/ 03 октября 2008

Только что нашел это в документах для iPhone

Если ваше приложение имеет графический пользовательский интерфейс, рекомендуется вы получаете пользовательские события и инициировать обновления интерфейса с вашего Основная тема приложения. это подход помогает избежать синхронизации проблемы, связанные с обработкой пользователя события и содержимое окна чертежа. Некоторые рамки, такие как Какао, как правило, требуют такого поведения, но это также имеет преимущество упрощение логики управления ваш пользовательский интерфейс.

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

0 голосов
/ 08 ноября 2008

Почти ни один из кода пользовательского интерфейса в UIKit или AppKit не является поточно-ориентированным. То, как он терпит неудачу, не имеет значения, потому что, если вы беспокоитесь о том, как это терпит неудачу, вы делаете что-то, что может привести ко всевозможным странным ошибкам, которые в любом случае будут тонко меняться между различными выпусками ОС.

Мой лучший совет - не использовать вещи из фоновых потоков, если в документах не указано, что это безопасно.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...