嵌套 DispatchQueue.main.async

Nested DispatchQueue.main.async

我在从 VC 调用的函数中显示警报。我不希望 main 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)
    }
}

显示警报不会阻塞线程。 present(_:animated:completion:) 不是阻塞操作,因此没有理由添加任何这些 .async 调用。

就是说,您不想尝试在 viewDidLoad 中显示警报。那还为时过早。你的视图控制器还没有出现在屏幕上。您应该将 showAlert() 放入 viewDidAppear,并删除所有 .async 调用。

作为一般规则,这些类型的模态警报在任何情况下都应该是最后的手段,尤其是当视图控制器出现在屏幕上时。通常,您应该将要呈现给用户的任何消息集成到视图本身,而不是阻塞整个 UI。但是如果警报是适当的(有时是),那么只要您在主队列中就可以直接显示它们。

你应该只把你必须的东西放在主线程上。所以你不应该把它包装在 viewDidLoad 函数的 main.async 块中。

您应该将其包装在具有不同优先级的 DispatchQueue 中。

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

您似乎对 DispatchQueue 有疑问:)

您的程序在 运行 时使用操作队列。此队列可以是系统定义的(如 main)或用户定义的。当您使用 DispatchQueue.main.async(_:) 时,您将代码块排入主队列。当他们的时间到了,主队列执行他们。

但是在 viewDidLoad(_:) 中,您已经在 main 队列中了。此外,调用 AlertController 的原因是 UI 操作,并且 UI 操作不能在除 main 之外的任何队列上完成,您不需要发送代码阻止任何队列,你不应该。

而且,正如@SeanRobinson159 所说,AlertController 在屏幕上时不会阻塞主线程。它与您的其他 ViewControllers.

一样工作

那么,在哪些情况下你应该使用DispatchQueue来调用AlertController

您应该使用 DispatchQueue.main.async(_:) 将执行 UI 操作(例如调用 AlertController 或更改 UILabel 的文本)的代码块从不同的队列发送到主队列队列。例如,您可能从事网络运营工作。您在不同的线程中进行操作,当结果出现时,您可以将进行 UI 操作的代码块发送到主队列。

您可以google GCD(Grand Central Dispatch) 获取详细信息。