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