Вложенный DispatchQueue.main.async - PullRequest
0 голосов
/ 11 марта 2019

Я показываю предупреждение в функции, которую я вызываю из VC.Я не хочу, чтобы основной ВК был заблокирован.Я вызываю эту функцию оповещения в асинхронном режиме.Функция в свою очередь имеет другую асинхронность.Это хорошая практика или я делаю это неправильно?

Кто-нибудь может порекомендовать хорошую практику для следующего кода?

class MyVC: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        // Don't block main thread
        DispatchQueue.main.async {
            self.showAlert(title: "Title", message: "Message")
        }

        // Do other stuff ...

    }
}

func showAlert(title: String = "", message: String) {

    alert = UIAlertController(title: title,message: message, preferredStyle: .alert)
    let cancelAction = UIAlertAction(title: "Ok", style: .cancel, handler: nil)
    alert.addAction(cancelAction)

    DispatchQueue.main.async {
        UIApplication.shared.keyWindow?.rootViewController!.present(alert, animated: true, completion: nil)
    }
}

Ответы [ 3 ]

3 голосов
/ 11 марта 2019

Отображение предупреждения не блокирует поток.present(_:animated:completion:) не является операцией блокировки, поэтому нет необходимости добавлять какие-либо из этих .async вызовов.

При этом вы не захотите пытаться представить предупреждение внутри viewDidLoad.Это слишком рано.Ваш контроллер просмотра еще не на экране.Вы должны поместить showAlert() в viewDidAppear и удалить все вызовы .async.

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

1 голос
/ 12 марта 2019

Кажется, у вас проблема с DispatchQueue:)

Ваша программа во время работы использует очереди операций.Эти очереди могут быть системными (например, main) или пользовательскими.Когда вы используете DispatchQueue.main.async(_:), вы помещаете блок кода в основную очередь.Когда наступит их время, основная очередь выполнит их.

Но в viewDidLoad(_:) вы уже в очереди main.Кроме того, причиной вызова AlertController является операция пользовательского интерфейса, и операции пользовательского интерфейса не могут быть выполнены ни в какой очереди, кроме main, вам не нужно отправлять свой блок кода в какую-либо очередь, и вы не должны.

А также, как сказал @ SeanRobinson159, AlertController не блокирует основной поток, когда он находится на экране.Он работает как ваш ViewControllers.

Итак, в каких случаях вы должны использовать DispatchQueue для вызова AlertController

Вы должны использовать DispatchQueue.main.async(_:) дляотправить блоки кода, которые выполняют операции пользовательского интерфейса (например, вызов AlertController или изменение текста UILabel), в основную очередь из другой очереди.Например, может быть, вы работаете в сети.Вы выполняете свою операцию в другом потоке, и когда приходит результат, Вы можете отправить свой блок кода, который выполняет операции пользовательского интерфейса, в основную очередь.

Вы можете использовать Google GCD (Grand Central Dispatch) для получения подробной информации.

0 голосов
/ 11 марта 2019

Вы должны поместить только то, что вам необходимо в основной поток. Поэтому не следует заключать его в блок main.async в функции viewDidLoad.

Вы должны обернуть его в DispatchQueue с другим приоритетом.

т.е. DispatchQueue.global(qos: .userInitiated).async { }

...