Почему операции UIKit должны выполняться в основном потоке?
Я пытаюсь понять, почему операции с пользовательским интерфейсом не могут выполняться с использованием нескольких потоков. Это также требование в других рамках, таких как OpenGL или cocos2d?
Как насчет других языков, таких как С# и javascript? Я пробовал искать в google, но люди упоминают о потоках POSIX, которые я не понимаю.
Ответы
Ответ 1
В Cocoa Нажмите UIApplication
, т.е. экземпляр вашего приложения присоединен к основному потоку, потому что этот поток создается UIApplicatioMain()
, функцией точки входа Cocoa Touch. Он устанавливает основной цикл событий, включая цикл запуска приложений, и начинает обработку событий. Цикл основного события приложения принимает все события пользовательского интерфейса, т.е. Касание, жесты и т.д.
Из документов UIApplicationMain()
,
Эта функция создает экземпляр объекта приложения из основного класса и создает экземпляр делегата (если есть) из данного класса и задает делегат для приложения. Он также устанавливает основной цикл событий, включая цикл запуска приложений, и начинает обработку событий. Если файл Info.plist приложений указывает основной загружаемый файл nib, включая ключ NSMainNibFile и действительное имя файла nib для значения, эта функция загружает этот файл nib.
Эти события пользовательского интерфейса приложения далее перенаправляются на UIResponder
, следуя цепочке ответчиков, как правило, как UIApplication
→ UIWindow
→ UIViewController
→ UIView
→ subviews (UIButton
и т.д.).
Ответчики обрабатывают события, такие как нажатие кнопки, кратковременное нажатие, увеличение зума, прокрутка и т.д., которые переводится как изменение в пользовательском интерфейсе. Следовательно, поскольку вы можете видеть, что эта цепочка событий встречается в основном потоке, поэтому UIKit
, структура, содержащая респондентов, должна работать в основном потоке.
Из документов снова UIKit
,
По большей части классы UIKit должны использоваться только из основного потока приложений. Это особенно справедливо для классов, полученных из UIResponder, или которые связаны с управлением пользовательским интерфейсом приложений любым способом.
ИЗМЕНИТЬ
Почему drawRect должен быть в основном потоке?
drawRect:
вызывается UIKit
как часть жизненного цикла UIView
. Поэтому drawRect:
привязан к основному потоку. Рисование таким образом дорого, потому что это делается с использованием центрального процессора. Аппаратное ускорение графики обеспечивается с помощью технологии CALayer (Core Animation).
CALayer
, с другой стороны, выступает в качестве хранилища поддержки для представления. После этого представление просто отобразит кэшированное растровое изображение текущего состояния. Любое изменение свойств вида приведет к изменениям в хранилище резервных копий, которые будут выполняться графическим процессором на резервной копии. Тем не менее, представление по-прежнему должно обеспечивать исходный контент и периодически обновлять представление. Я не работал над OpenGL, но я думаю, что он также использует слои (я мог ошибаться).
Я попытался ответить на это, насколько мне известно. Надеюсь, что это поможет!
Ответ 2
С# ведет себя одинаково (см., например, здесь: Поддерживать поток пользовательского интерфейса). Обновления пользовательского интерфейса должны выполняться в потоке пользовательского интерфейса - большинство других вещей должно выполняться в фоновом режиме.
Если это не так, вероятно, будет адский переход между всеми обновлениями, которые должны быть выполнены в пользовательском интерфейсе...
Ответ 3
from: https://www.objc.io/issues/2-concurrency/thread-safe-class-design/
Это сознательное дизайнерское решение со стороны Яблока, чтобы UIKit не был потокобезопасным. Сделать его потокобезопасным не будет покупать вам много с точки зрения производительности; это на самом деле делало бы что-то еще медленнее. И тот факт, что UIKit привязан к основному потоку, позволяет легко писать параллельные программы и использовать UIKit. Все, что вам нужно сделать, это убедиться, что вызовы в UIKit всегда выполняются в основном потоке.
Таким образом, в соответствии с этим тот факт, что объекты UIKit должны быть доступны в основном потоке, является дизайнерским решением Apple в пользу производительности.
Ответ 4
Потому что вы хотите, чтобы пользователь мог видеть изменения пользовательского интерфейса по мере их возникновения. Если бы вы могли выполнять изменения пользовательского интерфейса в фоновом потоке и отображать их по завершении, казалось бы, приложение не ведет себя правильно.
Все операции, отличные от UI (или, по крайней мере, те, которые являются очень дорогостоящими, например загрузка или создание запросов к базе данных), должны выполняться в фоновом потоке, тогда как все изменения пользовательского интерфейса должны всегда происходить в основном потоке, чтобы обеспечить как гладкие возможности пользователя.
Я не знаю, как это было в С# для приложений для Windows Phone, но я бы ожидал, что он будет таким же. В Android система даже не позволит вам делать что-то вроде загрузки в основном потоке, создавая фоновый поток напрямую.
Как правило, когда вы думаете о главном потоке, подумайте "что видит пользователь".
Ответ 5
Каждая система, каждая библиотека, должна заботиться о безопасности потоков и должна делать что-то для обеспечения безопасности потоков, в то же время заботясь о правильности и производительности.
В случае пользовательского интерфейса iOS и MacOS X было принято решение сделать поток потока пользовательского интерфейса безопасным, только позволив и выполнив методы пользовательского интерфейса в основном потоке. И это так.
Так как есть много сложных вещей, которые потребуются, по крайней мере, для сериализации, чтобы предотвратить полный хаос, я не вижу очень многого в том, чтобы разрешить интерфейс в фоновом потоке.