1

I want to display an alert screen using UIAlertController in viewDidAppear() and wait until the button is pressed (iOS 11).

When displaying UIAlertController by present, the alert screen is called in viewDidAppear(), but it is not displayed and the screen can not be tapped.

Alert screen by asynchronous or delayed execution. The alert screen is displayed without any problem.

Is there any good way to get in sync?

override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)

    var doneloop = false

    let alert = UIAlertController(title:"Title", message: "Message", preferredStyle: UIAlertControllerStyle.alert)

    let action1 = UIAlertAction(title: "OK", style: UIAlertActionStyle.default, handler: {
    (action: UIAlertAction!) in
       print("push OK button")

       doneloop = true // Runloop flag
    })

    alert.addAction(action1)

    self.present(alert, animated: false, completion: nil)

    while !doneloop {
       RunLoop.current.run(until: Date(timeIntervalSinceNow: 0.1))
    }

    alert.dismiss(animated: false, completion: nil)
}
gotnull
  • 26,454
  • 22
  • 137
  • 203
M.Gonbe
  • 11
  • 2
  • Please learn to understand how asynchronous API works. This way to force the alert controller to be synchronous is horrible and there is no reason to do that. – vadian Apr 17 '18 at 06:54
  • Look into DispatchGroup with its `wait()` function. That's a better solution than a while-loop. – LinusGeffarth Apr 17 '18 at 07:13

3 Answers3

-1

I have created this method, just pass required data to this function with completion handling.....

//Alert with handling
func showMessageWithAction(_ messageText:String, messageTitle:String, okButtonTitle:String, cancelButtonTitle:String?, vc: UIViewController, completion:@escaping (Bool) -> Void) {

    let attribute = NSMutableAttributedString.init(string: messageText)
    attribute.addAttribute(NSAttributedStringKey.foregroundColor, value: UIColor.white , range: NSRange(location: 0,length: messageText.count))

    let alert = UIAlertController(title: messageTitle,
                                  message: messageText,
                                  preferredStyle: 
UIAlertControllerStyle.alert)
    alert.view.tintColor = UIColor(red: (0/255.0), green: (29/255.0), blue: (97/255.0), alpha: 1.0)
    alert.addAction(UIAlertAction(title: okButtonTitle,
                                  style: UIAlertActionStyle.default,
                                  handler: {(alert: UIAlertAction!) in
                                    completion(true)
    }))
    if let cancelButton = cancelButtonTitle {
        alert.addAction(UIAlertAction(title: cancelButton,
                                      style: UIAlertActionStyle.cancel,
                                      handler: {(alert: UIAlertAction!) in
                                        completion(false)
        }))
    }
    vc.present(alert, animated: true, completion: nil)
}
Manish Mahajan
  • 2,062
  • 1
  • 13
  • 19
-1

The way you do it is pretty messy, there is no need to synchronize it.

Also I would recommend you to run the alert presentation in viewWillAppear instead of viewDidAppear in case that you want see the alert after every entrency into this UIViewController.

In case that you would like to run it once, use viewDidLoad

I've created a wrapper around UIAlertController.

struct AlertWrapper {
    static func presentAlert(for vc: UIViewController, with title: String, message: String, dismissAlertAction: UIAlertAction? = nil, applyAlertAction: UIAlertAction? = nil) {
        let alert = UIAlertController(title: title, message: message, preferredStyle: .alert)
        if dismissAlertAction != nil {
            alert.addAction(dismissAlertAction!)
        }
        if applyAlertAction != nil {
            alert.addAction(applyAlertAction!)
        }
        vc.present(alert, animated: true, completion: nil)
    }
}

Example inside methods above

let applyAction = UIAlertAction(title: "Ok", style: .default) { (_) in
    // What ever you would like to do after pressing 'Ok'
}

let dismissAction = UIAlertAction(title: "Cancel", style: .default) { (_) in
    // What ever you would like to do after pressing 'Cancel'
}

AlertWrapper.presentAlert(for: self, with: "YOUR TITTLE", message: "YOUR MESSAGE", dismissAlertAction: dismissAction, applyAlertAction: applyAction)

Fell free to ask any questions and next time please read rules here.

Example solution

Derp
  • 137
  • 1
  • 9
-2

Simple way

override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)

    let alert = UIAlertController(title:"Title", message: "Message", preferredStyle: UIAlertControllerStyle.alert)
    let action1 = UIAlertAction(title: "OK", style: UIAlertActionStyle.default)
    alert.addAction(action1)
    self.present(alert, animated: false, completion: nil)
}
Prateek kumar
  • 244
  • 3
  • 9