简体   繁体   English

嵌套DispatchQueue.main.async

[英]Nested DispatchQueue.main.async

I'm showing alert in a function which I call from VC. 我正在从VC调用的函数中显示警报。 I don't want main VC to be blocked. 我不希望主VC被阻止。 I'm calling this alert function in async. 我正在异步调用此警报功能。 The function in turn has another async. 该函数又具有另一个异步。 Is this good practice or I'm doing it wrong? 这是好的做法,还是我做错了?

Can anyone suggest good practice for following code? 有人可以建议遵循以下代码的良好做法吗?

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)
    }
}

Showing an alert doesn't block the thread. 显示警报不会阻塞线程。 present(_:animated:completion:) is not a blocking operation, so there's no reason to add any of these .async calls. present(_:animated:completion:)不是阻塞操作,因此没有理由添加任何这些.async调用。

That said, you wouldn't want to try to present an alert inside viewDidLoad . 就是说,您不想尝试在viewDidLoad内部显示警报。 That's far too early. 还为时过早。 Your view controller isn't on the screen yet. 您的视图控制器尚未显示在屏幕上。 You should put showAlert() in viewDidAppear , and remove all the .async calls. 您应该将showAlert()放在viewDidAppear ,并删除所有.async调用。

As a general rule, these kinds of modal alerts should be a last resort in any case, especially when a view controller is coming on screen. 作为一般规则,在任何情况下,尤其是在视图控制器出现在屏幕上时,此类模式警报都应是最后的手段。 Generally, you should integrate whatever message you want to present to the user into the view itself rather than blocking the entire UI. 通常,您应该将要呈现给用户的任何消息集成到视图本身,而不是阻塞整个UI。 But if an alert is appropriate (and sometimes they are), then you can just present them directly as long as you're on the main queue. 但是,如果警报是适当的(有时是警报),那么只要在主队列中就可以直接显示警报。

It seems you have a problem with DispatchQueue :) 看来您有DispatchQueue问题:)

Your program uses operation queues while running. 您的程序在运行时使用操作队列。 This queues can be system-defined(like main ) or user defined. 该队列可以是系统定义的(例如main )或用户定义的。 When you use DispatchQueue.main.async(_:) you enqueue a code block to main queue. 使用DispatchQueue.main.async(_:) ,会将代码块排队到主队列中。 When their time comes, main queue execute them. 时间到了,主队列执行它们。

But in viewDidLoad(_:) , you are already in main queue. 但是在viewDidLoad(_:) ,您已经在main队列中。 Also, cause of calling an AlertController is a UI operation and UI operations can't be done on any queue except main , you don't need to send your code block to any queue and you shouldn't. 另外,调用AlertController是UI操作,除了main之外,不能在任何队列上执行UI操作,您不需要将代码块发送到任何队列,也不需要。

And also, Like @SeanRobinson159 said, AlertController does not block main thread when it is on screen. 而且,就像@ SeanRobinson159所说的那样, AlertController在屏幕上时不会阻止主线程。 It works like your orther ViewControllers . 它的工作方式与您的ViewControllers

So, Which cases you should use DispatchQueue to call an AlertController 因此,在哪些情况下应使用DispatchQueue调用AlertController

You should use DispatchQueue.main.async(_:) to send code blocks that performs UI operations (like calling AlertController or changing UILabel 's text), to main queue from different queue. 您应该使用DispatchQueue.main.async(_:)将执行UI操作(如调用AlertController或更改UILabel的文本)的代码块从其他队列发送到主队列。 For example, maybe you work on an network operation. 例如,也许您从事网络运营。 You make your operation in different thread and when result comes, You can send your code block that makes UI operations, to main queue. 您在不同的线程中进行操作,并且在结果出现时,可以将进行UI操作的代码块发送到主队列。

You can google GCD(Grand Central Dispatch) for deatiled information. 您可以通过Google GCD(中央调度)获取详细信息。

You should only put what you have to on to the main thread. 您应该只把你有什么对主线程。 So you shouldn't wrap it in the main.async block in the viewDidLoad function. 因此,您不应将其包装在viewDidLoad函数的main.async块中。

You should wrap it in a DispatchQueue with a different priority. 您应该将它包装在具有不同优先级的DispatchQueue

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM