40

I've created a UIAlertView that contains a UIActivityIndicator. Everything works great, but I'd also like the UIAlertView to disappear after 5 seconds.

How can I Dismiss my UIAlertView after 5 seconds?

 var alert: UIAlertView = UIAlertView(title: "Loading", message: "Please wait...", delegate: nil, cancelButtonTitle: "Cancel");

 var loadingIndicator: UIActivityIndicatorView = UIActivityIndicatorView(frame: CGRectMake(50, 10, 37, 37)) as UIActivityIndicatorView
 loadingIndicator.center = self.view.center;
 loadingIndicator.hidesWhenStopped = true
 loadingIndicator.activityIndicatorViewStyle = UIActivityIndicatorViewStyle.Gray
 loadingIndicator.startAnimating();

 alert.setValue(loadingIndicator, forKey: "accessoryView")
 loadingIndicator.startAnimating()

 alert.show()
Serge Pedroza
  • 2,160
  • 3
  • 28
  • 41
  • If you are loading something, why would you want to hide the alert after a fixed time? Wouldn't you rather hide it when the loading is complete? – drewag Dec 23 '14 at 04:17

11 Answers11

100

A solution to dismiss an alert automatically in Swift 3 and Swift 4 (Inspired by part of these answers: [1], [2], [3]):

// the alert view
let alert = UIAlertController(title: "", message: "alert disappears after 5 seconds", preferredStyle: .alert)
self.present(alert, animated: true, completion: nil)

// change to desired number of seconds (in this case 5 seconds)
let when = DispatchTime.now() + 5
DispatchQueue.main.asyncAfter(deadline: when){
  // your code with delay
  alert.dismiss(animated: true, completion: nil)
}

Result:

enter image description here

ronatory
  • 7,156
  • 4
  • 29
  • 49
48

You can dismiss your UIAlertView after a 5 second delay programmatically, like so:

alert.show()

// Delay the dismissal by 5 seconds
let delay = 5.0 * Double(NSEC_PER_SEC)
var time = dispatch_time(DISPATCH_TIME_NOW, Int64(delay))
dispatch_after(time, dispatch_get_main_queue(), {
    alert.dismissWithClickedButtonIndex(-1, animated: true)
})
David
  • 3,285
  • 1
  • 37
  • 54
Lyndsey Scott
  • 37,080
  • 10
  • 92
  • 128
  • There is no need to create the 2nd function. Inside the `dispatch_after` block simply call `alert.dismissWithClickedButtonIndex(-1, animated: true)` – rmaddy Dec 23 '14 at 04:30
  • BTW - I like this approach better than using a timer. – rmaddy Dec 23 '14 at 04:30
  • 1
    @rmaddy It's more flexible, but more ugly. I can see why people would avoid it for aesthetic reasons alone. – Lyndsey Scott Dec 23 '14 at 04:32
14

For swift 4 you can use this code

let alertController = UIAlertController(title:"Alert",message:nil,preferredStyle:.alert)
self.present(alertController,animated:true,completion:{Timer.scheduledTimer(withTimeInterval: 5, repeats:false, block: {_ in
    self.dismiss(animated: true, completion: nil)
})})
Daniel
  • 20,420
  • 10
  • 92
  • 149
Vaishnavi
  • 419
  • 5
  • 9
13

in swift 2 you can do this. Credit to @Lyndsey Scott

 let alertController = UIAlertController(title: "youTitle", message: "YourMessage", preferredStyle: .Alert)
                self.presentViewController(alertController, animated: true, completion: nil)
                let delay = 5.0 * Double(NSEC_PER_SEC)
                let time = dispatch_time(DISPATCH_TIME_NOW, Int64(delay))
                dispatch_after(time, dispatch_get_main_queue(), {
                    alertController.dismissViewControllerAnimated(true, completion: nil)
                })
George Asda
  • 2,119
  • 2
  • 28
  • 54
  • What happen is there is an ok button on the alert and that the user clicks it before the dispatch is executed ? – Regis St-Gelais Apr 28 '16 at 17:24
  • I was wondering if it would crash since the alertControler would already dismissed if the user presed the ok button before the 5 seconds delay. I tryed it and I do not get any error message. So I guess it is ok. – Regis St-Gelais Apr 28 '16 at 18:26
  • On Android I made an auto-closing message box that updates the ok button caption with a countdown OK (5), OK(4), ....OK(1). I would very much like to do something similar but I don't think I can with an alertController. – Regis St-Gelais Apr 28 '16 at 18:29
6

Create the alert object as a global variable. You can use a NSTimer for this purpose.

var timer = NSTimer.scheduledTimerWithTimeInterval(5.0, target: self, selector: Selector("dismissAlert"), userInfo: nil, repeats: false)


func dismissAlert()
{
    // Dismiss the alert from here
    alertView.dismissWithClickedButtonIndex(0, animated: true)

}

NOTE:

Important: UIAlertView is deprecated in iOS 8. (Note that UIAlertViewDelegate is also deprecated.) To create and manage alerts in iOS 8 and later, instead use UIAlertController with a preferredStyle of UIAlertControllerStyleAlert.

Reference : UIAlertView

Midhun MP
  • 103,496
  • 31
  • 153
  • 200
1

For Swift 3

let alert = UIAlertController(title: “Alert”, message: “Message”,preferredStyle: UIAlertControllerStyle.alert)
self.present(alert, animated: true, completion: nil)
 DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + Double((Int64)(5.0 * Double(NSEC_PER_SEC))) / Double(NSEC_PER_SEC), execute: {() -> Void in
     alert.dismiss(animated: true, completion: {() -> Void in
 })
})
Yakup Ad
  • 1,591
  • 16
  • 13
1

@ronatory 's answer in c#

var when = new DispatchTime(DispatchTime.Now, 
TimeSpan.FromSeconds(5));
DispatchQueue.MainQueue.DispatchAfter(when, () =>
{
    // your code with delay
    alertController.DismissModalViewController(true);
});
jtth
  • 876
  • 1
  • 12
  • 40
1

In iOS 8.0+ UIAlertController inherits from UIViewController, so, it is just that, a view controller. So, all the restrictions apply. That's why when there's a possibility that the view gets dismissed by the user, it's not entirely safe to try to dismiss it without proper checks.

In the following snippet there's an example of how this can be achieved.

func showAutoDismissableAlert(
      title: String?,
      message: String?,
      actions: [MyActionWithPayload], //This is just an struct holding the style, name and the action in case of the user selects that option
      timeout: DispatchTimeInterval?) {

  let alertView = UIAlertController(
      title: title,
      message: message,
      preferredStyle: .alert
  )

  //map and assign your actions from MyActionWithPayload to alert UIAlertAction
  //(..)

  //Present your alert
  //(Here I'm counting on having the following variables passed as arguments, for a safer way to do this, see https://github.com/agilityvision/FFGlobalAlertController) 
  alertView.present(viewController, animated: animated, completion: completion)


  //If a timeout was set, prepare your code to dismiss the alert if it was not dismissed yet
  if let timeout = timeout {
    DispatchQueue.main.asyncAfter(
       deadline: DispatchTime.now() + timeout,
       execute: { [weak alertView] in
            if let alertView = alertView, !alertView.isBeingDismissed {
                alertView.dismiss(animated: true, completion: nil)
            }
        }
    }
}
Hugo Alonso
  • 6,684
  • 2
  • 34
  • 65
0

//Generic Function For Dismissing alert w.r.t Timer

/** showWithTimer */
public func showWithTimer(message : String?, viewController : UIViewController?) {

    let version : NSString = UIDevice.current.systemVersion as NSString
    if  version.doubleValue >= 8 {
        alert = UIAlertController(title: "", message: message, preferredStyle:.alert)
        viewController?.present(alert ?? UIAlertController(), animated:true, completion:nil)
        let when = DispatchTime.now() + 5
        DispatchQueue.main.asyncAfter(deadline: when){
            self.alert?.dismiss(animated: true, completion: nil)
        }
    }
}
Pratyush Pratik
  • 683
  • 7
  • 14
0

You can make it as an extension to reuse the disappearing alert in multiple view controllers.

extension UIViewController {
func disappearingAlert(title: String, message: String){
    // the alert view
    let alert = UIAlertController(title: title, message: message, preferredStyle: .alert)
    self.present(alert, animated: true, completion: nil)

    // change to desired number of seconds (in this case 5 seconds)
    let when = DispatchTime.now() + 5
    DispatchQueue.main.asyncAfter(deadline: when){
      // your code with delay
      alert.dismiss(animated: true, completion: nil)
    }
}

}

-1

I'm not an expert but this works for me and I guess is easier

let alert = UIAlertController(title: "", message: "YOUR MESSAGE", preferredStyle: .alert)
present(alert, animated: true) {
   sleep(5)
   alert.dismiss(animated: true)
}
Stephen Rauch
  • 47,830
  • 31
  • 106
  • 135