45

I am presenting the UIAlertController on the main thread as :

class HelperMethodClass: NSObject {

    class func showAlertMessage(message:String, viewController: UIViewController) {
        let alertMessage = UIAlertController(title: "", message: message, preferredStyle: .alert)

        let cancelAction = UIAlertAction(title: "Ok", style: .cancel)

        alertMessage.addAction(cancelAction)

        DispatchQueue.main.async {
            viewController.present(alertMessage, animated: true, completion: nil)
        }
    }
}

And I am calling the method from any UIViewController as:

HelperMethodClass.showAlertMessage(message: "Any Message", viewController: self)

I am getting the output properly.

But in console I am getting below message:

[Assert] Cannot be called with asCopy = NO on non-main thread.

Is there something I have done wrong here or I can ignore this message ?

Edit

Thanks to @NicolasMiari :

Adding below code is not showing any message:

DispatchQueue.main.async {
    HelperMethodClass.showAlertMessage(message: "Any Message", viewController: self)
}

What can be the reason that previously it was showing the message in console?

Amit
  • 4,837
  • 5
  • 31
  • 46
  • 3
    Did you try moving _everything_ (starting from `let alertMessage =...`) to withing the `async` block? – Nicolas Miari Oct 15 '18 at 05:20
  • Also: Did you try setting up a breakpoint and stepping, to see which line triggers the warning? What thread does the `showAlertMesdsage()` method run on, when seen on the call stack? – Nicolas Miari Oct 15 '18 at 05:21

1 Answers1

85

You should call all code from showAlertMessage on main queue:

class func showAlertMessage(message:String, viewController: UIViewController) {
    DispatchQueue.main.async {
        let alertMessage = UIAlertController(title: "", message: message, preferredStyle: .alert)

        let cancelAction = UIAlertAction(title: "Ok", style: .cancel)

        alertMessage.addAction(cancelAction)

        viewController.present(alertMessage, animated: true, completion: nil)
    }
}
Ilya Kharabet
  • 4,203
  • 3
  • 15
  • 29
  • 4
    Why is this needed? – nonolays Dec 11 '18 at 20:17
  • 2
    @nonolays Watch this video. https://www.youtube.com/watch?v=iTcq6L-PaDQ – Jeff Feb 01 '19 at 17:39
  • 4
    @Jeff This video does not provide an answer to the question. I'm also interested in the why we need to instantiate UIAlertController on the main thread. – Vin Gazoil May 11 '19 at 14:11
  • 2
    @VinGazoil Any time you update the UI you need to be on the main thread. I can't say as to why the UIAlertController is not already on the main but print(Thread.isMainThread) will tell you if you're on the main. – Jeff Jun 01 '19 at 21:33
  • Nice! I was seeing this from an RxSwift extension...just had to wrap the actual creation of the alertController and actions creations all up in the main queue. Problem solved. Cheers! – Mike Critchley Jun 17 '19 at 19:07
  • 5
    It's still very unclear to me why the creation of the UIAlertController needs to be in the main thread...we were getting really funky behavior without this (people couldn't tap on random parts of their screen). – monstermac77 Oct 20 '20 at 20:04
  • 2
    I know it's strange, but any view controller should be instantiated on the main thread, not just at the time of presentation. At any time before presentation, a view controller might load its views or even modify them, in response to some public method usage. – androidguy Mar 07 '21 at 10:29