Можно ли создать UIViewController в фоновом потоке?

Связанный: Можно ли создать UIView на фоновая ветка?

Безопасен ли этот код фонового потока?

let viewController = MyViewController(nibName: nil, bundle: nil)
viewController.title = "My Title"
viewController.myProperty = true
dispatch_async(dispatch_get_main_queue(), {
    self.navigationController?.pushViewController(viewController, animated: true)
})

person ma11hew28    schedule 03.11.2015    source источник
comment
Спасибо! :-) Значит, MyViewController(nibName: nil, bundle: nil) не запускает никаких обновлений пользовательского интерфейса? viewController.myProperty = true не имеет побочных эффектов. Это простое свойство.   -  person ma11hew28    schedule 04.11.2015


Ответы (2)


Это зависит от того, что на самом деле делают переменные экземпляра. Общее правило заключается в том, что код, выполняемый фоновым потоком, не должен запускать какие-либо обновления пользовательского интерфейса, такие как view.addSubview(..) или view.setNeedsLayout и т. д., тогда можно безопасно экспериментировать с контроллером представления, используя фоновый поток.

Другим примером могут быть навигационные контроллеры. Например, после того, как контроллер представления был помещен в стек навигации, даже обновление viewController.title может быть опасным, поэтому вы должны убедиться, что viewController.myProperty = true не запускает никаких обновлений пользовательского интерфейса. Лично я бы выполнил следующие задания в основном потоке, чтобы чувствовать себя в безопасности:

dispatch_async(dispatch_get_main_queue(), {
  viewController.title = "My Title"
  viewController.myProperty = true
  ...
})

Короче говоря, вы можете инициализировать новый UIView или UIViewController (или любой UIResponder) в фоновом потоке, однако вы должны изменить любое из его свойств, запускающих обновления пользовательского интерфейса в основном потоке. Так что создавайте в фоновом режиме, но обновляйте в основном потоке.

person ozgur    schedule 22.12.2015
comment
Я считаю, что обработки некоторых свойств в основной очереди будет недостаточно, чтобы обойти проблемы здесь. Само по себе перемещение контроллера представления в стек навигации — это то, что следует делать в основной очереди; в то время как все методы жизненного цикла контроллера представления будут вызываться (а также layoutsubviews и т. д. объекта представления контроллеров представления). В общем, небезопасно! - person antonio; 31.08.2016
comment
@antonio Я думаю, у тебя проблемы с пониманием того, что ты читаешь. Мы в принципе говорим одно и то же. Совершенно безопасно инициализировать контроллер представления в любом потоке, но как только обновления пользовательского интерфейса вступают в игру, вы всегда должны делать это в основной очереди. Создание контроллера представления не вызовет никаких методов, касающихся его жизненного цикла, таких как viewDidLoad, viewWillAppear или viewDidLayoutSubviews. - person ozgur; 31.08.2016
comment
Я не говорю о создании; Я говорю о проталкивании в стек навигации. - person antonio; 01.09.2016
comment
добавление в стек навигации — это обновление пользовательского интерфейса, поэтому оно должно обрабатываться в основной очереди. - person ozgur; 02.09.2016

Кажется, что ответ @ozgur устарел. Если вы попытаетесь создать UIViewController из фонового потока в последней версии Xcode (Версия 11.5 на момент написания), вы получите следующую ошибку:

-[UIViewController init] must be used from main thread only
person pls    schedule 19.06.2020