Alerts and action sheets in iOS 8

Before iOS 8, if you wanted to alert the user about something, you would use an UIAlertView like this:

UIAlertView *alertView = [[UIAlertView alloc]
                          initWithTitle:@"Pre iOS 8 style"
                          message:@"Old style alert"
                          delegate:self
                          cancelButtonTitle:@"Cancel"
                          otherButtonTitles:@"OK", nil];
    
[alertView show];

In iOS 8, UIAlertView is deprecated. Instead we have a brand new and more flexible way to present alerts (and action sheets). It’s called UIAlertController. So let’s see how we would display a simple alert using this new controller.

let alert = UIAlertController(title: "New alert style", 
                            message: "This alert is displayed using a UIAlertController", 
                     preferredStyle: .Alert)
        
let cancelAction = UIAlertAction(title: "Cancel", style: .Cancel , handler: nil)
alert.addAction(cancelAction)
        
presentViewController(alert, animated: true, completion: nil)

This will display the following alert:

firstAlertThere are a few differences to the way we used to configure the UIAlertView. Let’s go over them. First we create an alert controller and give it a title, a message and a style. UIAlertController replaces UIAlertView and UIActionSheet classes, so we can choose what we want to display. You can also associate actions with your alert controller and give the user a way to respond. We have created only a cancel action, but you can create more than just one. The block based API is very handy. You just specify a block of code that will be executed when the user taps on the button corresponding to the action you’re specifying. We’ll see that in our next example.

And finally, showing the alert means that you need to present the alert controller, just like you would present any other view controller. Again, you can specify a block of code that can be executed on completion of presenting the controller. It’s not complicated, just different and much more flexible than before.

Let’s see another example where we customise the alert a bit more.

let alert = UIAlertController(title: "Feedback alert",
                            message: "Update your feedback in the text field ",
                     preferredStyle: .Alert)
        
let deleteAction = UIAlertAction(title: "Delete", style: .Destructive , handler: nil)
alert.addAction(deleteAction)
        
alert.addTextFieldWithConfigurationHandler { (textField) -> Void in
    textField.placeholder = "Enter feedback"
}
        
let updateAction = UIAlertAction(title: "Update", style: .Default) { (action) -> Void in
            
    let feedbackTextField: UITextField = alert.textFields?.first as UITextField
    let text = feedbackTextField.text
    println("You have updated your feedback to: \(text)")
}
alert.addAction(updateAction)

presentViewController(alert, animated: true, completion: nil)

This is how it will look:

secondAlert

There are a few things to notice in the code above. First of all, we have replaced our cancel action by a destructive action like delete. Set the style of the action as destructive and it will be displayed accordingly (red text colour and positioned on the left).
Next we are adding a text field where the user can enter some text. In the configuration handler we are adding a placeholder text for the text field. You can add more than one text field and we’ll see how we can use this to create a login alert in just a moment.
Next we are creating an update action. We have provided a handler for this action and all that we are doing is getting the text from the text field and logging it to the console. We use the alert controller to access the text field.
The final alert example is a login dialog:
let alert = UIAlertController(title: "Login", 
                            message: "Please enter your username and password", 
                     preferredStyle: .Alert)
        
alert.addTextFieldWithConfigurationHandler { (textField) -> Void in
     textField.placeholder = "Enter username"
}
        
alert.addTextFieldWithConfigurationHandler { (textField) -> Void in
      textField.placeholder = "Enter password"
      textField.secureTextEntry = true
}
        
let cancelAction = UIAlertAction(title: "Cancel", style: .Cancel , handler: nil)
alert.addAction(cancelAction)
        
let loginAction = UIAlertAction(title: "Login", style: .Default) { (action) -> Void in
            
     println("You have been logged in")
}
alert.addAction(loginAction)
        
presentViewController(alert, animated: true, completion: nil)

It will look like this:

loginAlertThe code is very similar to the previous one. We add two text fields, one for the username and one for the password and we make sure that the password doesn’t show. This makes creating login dialogs very easy.

Action Sheet

The action sheet is used when we want to present the user with a set of choices. Unlike the alert, the action sheet is displayed differently on iPad and iPhone. On iPhone the action sheet will rise from the bottom of the screen. On iPad an action sheet will be displayed in a popover.

Let’s see an example where we display a simple action sheet:

let alert = UIAlertController(title: "Action Sheet", 
                            message: "Please choose an action", 
                     preferredStyle: .ActionSheet)
        
let cancelAction = UIAlertAction(title: "Cancel", style: .Cancel , handler: nil)
alert.addAction(cancelAction)
        
let deleteAction = UIAlertAction(title: "Delete", style: .Destructive , handler: nil)
alert.addAction(deleteAction)
        
let anotherAction = UIAlertAction(title: "Default option", style: .Default) { 
        (alertAction) -> Void in 
        println("done!")
}
alert.addAction(anotherAction)

presentViewController(alert, animated: true, completion: nil)

As you can see, when creating the alert controller we need to specify that it’s going to be an action sheet. We create and add actions just the same as we’ve seen for alerts. We can’t add text fields to an action sheet, if you try you will get a runtime exception. The Cancel button, if present, will always be displayed at the bottom. The other buttons are displayed in the order of which the actions were added to the alert controller. You should add the destructive action first (delete, reset).

If you run this code on iPad it will crash.

Terminating app due to uncaught exception ‘NSGenericException’, reason: ‘Your application has presented a UIAlertController (<UIAlertController: 0x79672730>) of style UIAlertControllerStyleActionSheet. The modalPresentationStyle of a UIAlertController with this style is UIModalPresentationPopover. You must provide location information for this popover through the alert controller’s popoverPresentationController. You must provide either a sourceView and sourceRect or a barButtonItem.  If this information is not known when you present the alert controller, you may provide it in the UIPopoverPresentationControllerDelegate method -prepareForPopoverPresentation.’

The action sheet will be presented in a popover on iPad. A popover needs an anchor point and we are using a UIButton for this. We should use a UIBarButtonItem instead or we need to set a source view. The error is actually very helpful in this case. We can fix this by setting our button as the source view for the popover:

You will notice that the action sheet only has two actions, there is no Cancel button. We can easily get rid of the popover by tapping outside its area, so there is no need for a Cancel button.

Alerts and action sheets are just as easy to use in iOS 8 as they were before. You do have to write a bit more code but the flexibility you get for that is worth the trouble.

Leave a Reply

Your email address will not be published. Required fields are marked *

*