简体   繁体   中英

Nested DispatchQueue.main.async

I'm showing alert in a function which I call from VC. I don't want main VC to be blocked. 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.

That said, you wouldn't want to try to present an alert inside 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.

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. 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 :)

Your program uses operation queues while running. This queues can be system-defined(like main ) or user defined. When you use DispatchQueue.main.async(_:) you enqueue a code block to main queue. When their time comes, main queue execute them.

But in viewDidLoad(_:) , you are already in main queue. 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.

And also, Like @SeanRobinson159 said, AlertController does not block main thread when it is on screen. It works like your orther ViewControllers .

So, Which cases you should use DispatchQueue to call an 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. 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.

You can google GCD(Grand Central Dispatch) for deatiled information.

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.

You should wrap it in a DispatchQueue with a different priority.

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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