When needing to put an alert on the view of your app the previous way to handle this was with a UIAlertView or UIActionSheet. Both of these were deprecated in iOS 8 which means if you are targeting newer versions of iOS, which you should be in many cases, you now need to use UIAlertController. If you want to see how alerts worked in iOS 8 or below, you can find an example in the Location Authorization tutorial we made a few years ago.
The UIAlertController
UIAlertController became available in the iOS 8.0 SDK. Rather than go through the differences between this class and the previously used classes we’ll just look at what can be done with the UIAlertController.
Lets begin by creating a new single view project in Xcode making sure you select Swift as the language.
When created, open the Main.storyboard file. Drag out 2 buttons, one titled “Show Alert”, and the other titled “Show Action”. Open up the assistant editor (middle button seen to the left here) and with the storyboard on the left and the ViewController class on the right, CTRL+drag from one of the buttons to the class on the right side of the screen. When a message pops up asking you to insert outlet, action, etc… let go and a dialog box will appear. Change Connection to an Action, give it a friendly name (I just chose the same title as I put on the button), change type to UIButton, change Arguments to none. Hit OK. Repeat the process for the other button.
When done, close the assistant editor and then select ViewController.swift.
@IBAction func showAlert() { let alertController = UIAlertController.init(title: "A Title", message: "A Message", preferredStyle: .alert) let cancel = UIAlertAction.init(title: "Cancel", style: .cancel, handler: { action in print(action) }) let ok = UIAlertAction.init(title: "OK", style: .default, handler: { action in print(action) }) let destructive = UIAlertAction.init(title: "Destructive", style: .destructive, handler: { action in print(action) }) alertController.addAction(cancel) alertController.addAction(ok) alertController.addAction(destructive) self.present(alertController, animated: true, completion: nil) }
Paste the following code. This is how you get an alert view to show. I’ll talk you through it.
Line 2: Here we create the alert controller. This is what appears on screen when you tell it to. It has a title, a message, and a preferred style. The title and message are both optional. The preferred style has 2 options. One is .alert and the other is .actionSheet. Here, we’re declaring an alert.
If you commented out lines 3 to 14 and just let line 15 run then it would now show an alert, but you’d quickly see that there are no buttons on the alert to dismiss or accept.
Line 3 is where we create a cancel button. We give it the title string of “Cancel” but the style of the button is determined by specifying .cancel. After that, we have a completion handler which specifies action as an argument. This part is called if the cancel button is tapped.
Line 6 is similar to line 3, but we create a .default styled button. I just put a title of “OK” on it here.
Line 9 is also the same but this time it’s a .destructive style button. These contain red text and indicate to the user that something destructive will happen such as deleting data.
Lines 12, 13, 14 are where we add each of the actions to the alert controller. If you prefer, you can also add each UIAlertAction to an array and add them to the actions property.
Line 15 is where we present the alert controller.
Running the app now will allow you to see how the standard UIAlertController works. The arrangement of the buttons on screen depends on how many you have. If it’s 1 or 2, they run horizontal next to each other. 3 or more stacks them up vertically in the order that they were added with the exception of Cancel which is at the bottom of the list.
One last property that is available is the prefferedAction. This is for .alert only (not .actionSheet). If this is chosen for one of the buttons then this button receives the highlighting and not the Cancel button. If the user is interacting with an attached keyboard, the preferred action, when specified, is the one that is tapped when hitting enter on the keyboard. The preferred action needs to be added after the addAction is called for the action you are adding. If adding this to the above code, insert it at line 14 moving the destructive addAction down a line.
alertController.preferredAction = ok
Next, we can test the same but as an actionSheet. You have 2 options here. You can either go to line 2 of the code above and change .alert to .actionSheet, or you can go to the second IBAction we created and use the same code with the .actionSheet specified instead.
@IBAction func showAction() { let alertController = UIAlertController.init(title: "A Title", message: "A Message", preferredStyle: .actionSheet) let cancel = UIAlertAction.init(title: "Cancel", style: .cancel, handler: { action in print(action) }) let ok = UIAlertAction.init(title: "OK", style: .default, handler: { action in print(action) }) let destructive = UIAlertAction.init(title: "Destructive", style: .destructive, handler: { action in print(action) }) alertController.addAction(cancel) alertController.addAction(ok) alertController.addAction(destructive) self.present(alertController, animated: true, completion: nil) }
In a live app it would be unlikely that you would repeat all that code with just a single change, but for the purposes of this quick tutorial, it’s acceptable so that you can see both working side by side.
Adding Text Fields to a UIAlertController
The UIAlertController class is quite small with only a few features that can be used. The other and final option is to add a text field, or text fields (if you require more than one) to the alertController. They are stacked on top of each other and are ideal for entering information such as a username/password and also have many other uses.
Getting them to work is a little more tricker than a standard button with a completion handler, although it’s not overly complicated.
Modify the showAlert function so that it contains the following:
@IBAction func showAlert() { let alertController = UIAlertController.init(title: "A Title", message: "A Message", preferredStyle: .alert) let cancel = UIAlertAction.init(title: "Cancel", style: .cancel, handler: { action in print(action) }) let destructive = UIAlertAction.init(title: "Destructive", style: .destructive, handler: { action in print(action) }) let save = UIAlertAction.init(title: "Save", style: .default, handler: { action in let textField = alertController.textFields![0] as UITextField print(textField.text!) }) alertController.addTextField { (textField) in textField.placeholder = "Enter Search Term" } alertController.addAction(cancel) alertController.addAction(save) alertController.addAction(destructive) self.present(alertController, animated: true, completion: nil) } func search(searchString: String) { print(search) }
The main differences here are found on lines 9 to 16. Lets start with lines 14 to 16. Here is the part where we add a textfield to the alertController. You might want to add several. Repeat this code for each one. You can also set the properties in the completion handler here such as setting placeholder text as well as adjusting the other properties of the UITextField such as text alignment, if it should act as a password field, and so on.
Back to lines 9 – 12, we create a UIAlertAction like we did previously with the OK, Cancel, and other buttons. When the button is tapped, the completion handler is called. On line 10 we are accessing the first of the textfields in the array by specifying item [0]. We store the contents in the textField constant and on line 11 we log the text property of the textfield to the console.
Just remember to add the save action on line 19.
So the process in short is:
1. Add the textfield to the alertController and set the properties of the textfield in the completion handler.
2. Create the alert action and in the completion handler access the textfields property which is an array. Access the relevant item in that array (text fields are in order, so item 0 is the top one, item 1 is the second text field and so on).
3. Call whatever function you want in the completion handler. Here we are just logging to the console, but we could have another function or method that we call, such as something to validate the username and password.
When you run the project now you will see a textField which you can enter text in to. If you enter text and hit save, you will see that text in the console.
This concludes the tutorial. You can download the full project here.
Marvin Shapiro says
I just tried your “simple” UIAlertController example.
No alert unless I click the Show Alert button. How do I trigger the alert without clicking a button?
Too difficult for me.
Matthew says
If you let me know what the trigger is that you want to use, I can provide an example.
David says
Hi Matthew,
Good post. How can we show the alert after a new viewcontroller has been shown?
I’m trying it in the viewDidLoad section but keep getting the error:
“Warning: Attempt to present on whose view is not in the window hierarchy!”
I’ve also tried using ViewDidAppear and ViewDidLoad but can’t get it to show that way.
Any suggestions would appreciated..
Thanks in advance.
Matthew says
How are you showing the new view controller?