Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Loop over multiple UIAlertController's

In some cases my applications needs to display muliple Alert messages. Error messages are gathered on start and needs to be displayed to the user one at a time. When the first one is acknowledged, the next one should be presented. The problem is that they all try to execute at the same time, obviously. Is there a smart way to do this synchronously? Here is some code that simply describes what I want to do:

var errors : [NSError]!

override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view, typically from a nib.

    let error1 = NSError(domain: "Test1", code: 1, userInfo: [NSLocalizedFailureReasonErrorKey : "Test1 reason."])

    let error2 = NSError(domain: "Test2", code: 2, userInfo: [NSLocalizedFailureReasonErrorKey : "Test2 reason."])

    let error3 = NSError(domain: "Test3", code: 2, userInfo: [NSLocalizedFailureReasonErrorKey : "Test3 reason."])

    errors = [error1, error2, error3]

}

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

    for error in errors {

        self.showAlert(error)

    }

}

func showAlert(error: NSError) {

    var alert = UIAlertController(title: error.domain, message: error.localizedDescription, preferredStyle: .Alert)
    alert.addAction(UIAlertAction(title: "OK", style: .Default, handler:nil))

    self.presentViewController(alert, animated: true, completion: nil)
}
like image 426
fisher Avatar asked Mar 11 '15 21:03

fisher


1 Answers

You are almost there. Having a buffer of alert messages is the correct idea. But instead of showing all the alerts immediately, you should move the showAlert() call to the handler of the UIAlertAction. So if one alert is dismissed, the next will be shown.

Something like this:

var errors : [NSError]!

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

    let error1 = NSError(domain: "Test1", code: 1, userInfo: [NSLocalizedFailureReasonErrorKey : "Test1 reason."])
    let error2 = NSError(domain: "Test2", code: 2, userInfo: [NSLocalizedFailureReasonErrorKey : "Test2 reason."])
    let error3 = NSError(domain: "Test3", code: 2, userInfo: [NSLocalizedFailureReasonErrorKey : "Test3 reason."])

    errors = [error1, error2, error3]

    showError() // show an alert if errors are queued
}

func showError() {
    if let error = errors.first {
        let alert = UIAlertController(title: error.domain, message: error.localizedDescription, preferredStyle: .Alert)
        let okayAction = UIAlertAction(title: "OK", style: .Default) { action in
            self.errors.removeAtIndex(0) // remove the message of the alert we have just dismissed

            self.showError() // show next alert if there are more errors queued
        }
        alert.addAction(okayAction)
        presentViewController(alert, animated: true, completion: nil)
    }
    else {
        println("All alerts shown")
    }
}

Word of advice: Dismissing multiple alerts is very annoying. Maybe you could create a dedicated full screen viewController that shows all the error messages in a UITableView or something. This of course depends on the number of alert messages a typical user will see. If it's regularly more than three I would use a modal UIViewController which shows all messages at a glance.

like image 125
Matthias Bauch Avatar answered Oct 02 '22 23:10

Matthias Bauch