UIAlertController Changes in iOS 8
As part of the theme of iOS 8 to make interfaces adaptive there are some major changes to the presentation of view controllers. The new UIPresentationController does a lot of the hard work of animating view controller transitions and adapting to device size changes such as rotation. It also brings some big changes to some old UIKit favourites such as alert views, action sheets, popovers and search bar controllers. This post will be a gentle introduction to this new world by looking at the changes to alert views and action sheets.
UIAlertView - Alerting the Old Way
The last time I wrote about alert views was back in 2011 to describe the UIAlertView changes in iOS 5 . The release of iOS 5 brought alert view styles but not much else has changed since then. The code snippet below is all it takes to setup and present an alert view with cancel and OK buttons:
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"DefaultStyle" message:@"the default alert view style" delegate:self cancelButtonTitle:@"Cancel" otherButtonTitles:@"OK", nil];[alertView show];
The introduction of alert view styles in iOS 5 added a limited ability to create custom alerts by setting the alertViewStyle property. This extended the plain default button-only style to allow plain text input, secure text input or even a login and password input alert:

The UIAlertViewDelegate protocol has callback methods for the button actions and also a method (alertViewShouldEnableOtherButton:) called when a text field changes to allow buttons to be dynamically enabled/disabled.
UIAlertController - Adaptive Alerting
In the new adaptive world of iOS 8 the UIAlertController is a functionally identical, block-based replacement for both UIAlertView and UIActionSheet. Switching between an alert or action sheet is done by setting the preferred style when creating the controller.
A Simple Alert
It is interesting to compare the code required to setup a new style alert to the old UIAlertView. The creation of the basic UIAlertController is very similar to creating an UIAlertView (the alertTitle and alertMessage are both NSString’s):
UIAlertController *alertController = [UIAlertControlleralertControllerWithTitle:alertTitlemessage:alertMessagepreferredStyle:UIAlertControllerStyleAlert];
There is no delegate, nor do we initially specify the buttons. Note the third parameter which chooses between the alert and action sheet styles.
You add action buttons by creating an instance of UIAlertAction which you then add to the controller. The UIAlertAction consists of a title string, style and a block to execute when the user selects the action. The three possible choices for the UIAlertActionStyle cover default, cancel and destructive actions. To reproduce the classic cancel/ok action sheet we just need to create and add the two alert actions:
UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:NSLocalizedString(@"Cancel", @"Cancel action")style:UIAlertActionStyleCancelhandler:^(UIAlertAction *action){NSLog(@"Cancel action");}];UIAlertAction *okAction = [UIAlertAction actionWithTitle:NSLocalizedString(@"OK", @"OK action")style:UIAlertActionStyleDefaulthandler:^(UIAlertAction *action){NSLog(@"OK action");}];[alertController addAction:cancelAction];[alertController addAction:okAction];
Finally we can present the alert view controller as with any other view controller:
[self presentViewController:alertController animated:YES completion:nil];

The display order for the buttons depends on the order they are added to the alert controller. If you follow the iOS Human Interface Guidelines you should make the default action the right button and the cancel button the left button for a two button alert. You can only have one cancel action, if you add a second you will get a runtime exception:
*** Terminating app due to uncaught exception ‘NSInternalInconsistencyException’, reason: ‘UIAlertController can only have one action with a style of UIAlertActionStyleCancel’
Destructive actions
Here is a quick example of the third alert action style for destructive actions. The code is the same as before except that we add a “reset” button instead of the “ok” button:
UIAlertAction *resetAction = [UIAlertAction actionWithTitle:NSLocalizedString(@"Reset", @"Reset action") style:UIAlertActionStyleDestructive handler:^(UIAlertAction *action) { NSLog(@"Reset action"); }];[alertController addAction:resetAction];[alertController addAction:cancelAction];[self presentViewController:alertController animated:YES completion:nil];

Note that this time the destructive action is added first to make it appear on the left.
Text Input Alerts
The greater flexibility of the UIAlertController means that you no longer need to be constrained by the built-in styles for plain text, secure text or login and password input alert views. We can add an arbitrary number of UITextField objects to the alert and use all of the standard UITextField configuration options. When you add the text field to the alert controller you specify a block that is used to configure the text field.
For example, to recreate the old login and password style alert we can add two text fields and configure them with the appropriate placeholder text and set the password field to use secure text entry:
UIAlertController *alertController = [UIAlertControlleralertControllerWithTitle:alertTitle message:alertMessagepreferredStyle:UIAlertControllerStyleAlert];[alertController addTextFieldWithConfigurationHandler:^(UITextField *textField) { textField.placeholder = NSLocalizedString(@"LoginPlaceholder", @"Login"); }];[alertController addTextFieldWithConfigurationHandler:^(UITextField *textField) { textField.placeholder = NSLocalizedString(@"PasswordPlaceholder", @"Password"); textField.secureTextEntry = YES; }];
The values of the text field can be retrieved in the OK action handler:
UIAlertAction *okAction = [UIAlertActionactionWithTitle:NSLocalizedString(@"OK", @"OK action")style:UIAlertActionStyleDefaulthandler:^(UIAlertAction *action){UITextField *login = alertController.textFields.firstObject;UITextField *password = alertController.textFields.lastObject;...}];

Things get a little more complicated if we want to reproduce the behaviour of the old UIAlertView delegate method alertViewShouldEnableOtherButton: . Assume we only want to enable the OK button if the user has entered at least 3 characters in the login field. There is no equivalent delegate method for UIAlertController so we need to add an observer to the login text field. We can do that with the following code snippet in the configuration block:
[alertController addTextFieldWithConfigurationHandler:^(UITextField *textField) {...[[NSNotificationCenter defaultCenter] addObserver:selfselector:@selector(alertTextFieldDidChange:)name:UITextFieldTextDidChangeNotificationobject:textField]; }];
We need to remove the observer when the view controller is dismissed by adding the appropriate code to the handler block for each of the actions (and anywhere else we may dismiss the alert controller). For example in the okAction block we saw earlier:
UIAlertAction *okAction = [UIAlertAction actionWithTitle:NSLocalizedString(@"OK", @"OK action")style:UIAlertActionStyleDefaulthandler:^(UIAlertAction *action){...[[NSNotificationCenter defaultCenter] removeObserver:self name:UITextFieldTextDidChangeNotification object:nil];}];
Before presenting the alert controller we can disable the OK action:
okAction.enabled = NO;
Then in the notification observer we can check the login text field for content before changing the state back to enabled:
- (void)alertTextFieldDidChange:(NSNotification *)notification{UIAlertController *alertController = (UIAlertController *)self.presentedViewController;if (alertController){UITextField *login = alertController.textFields.firstObject;UIAlertAction *okAction = alertController.actions.lastObject;okAction.enabled = login.text.length > 2;}}
The alert view is now presented with the OK button disabled unless there are at least three characters in the login text field:

Action Sheet
The action sheet is used when you need to present the user with a set of choices. Unlike the alert view which is always presented as a modal view the presentation of the action sheet depends on the device size. On an iPhone (compact width) the action sheet rises from the bottom of the screen. On an iPad (regular width) an action sheet is always shown in a popover.
The creation of an action sheet is almost identical to an alert, the only difference being the style:
UIAlertController *alertController = [UIAlertController alertControllerWithTitle:alertTitlemessage:alertMessage preferredStyle:UIAlertControllerStyleAlert];
You add actions the same way as you do for alerts so I will abbreviate the code to add three actions:
UIAlertAction *cancelAction = ...;// UIAlertActionStyleCancelUIAlertAction *deleteAction = ...;// UIAlertActionStyleDestructiveUIAlertAction *archiveAction = ...; // UIAlertActionStyleDefault[alertController addAction:cancelAction];[alertController addAction:deleteAction];[alertController addAction:archiveAction];
You cannot add text fields to action sheets, if you try it you will get a runtime exception:
*** Terminating app due to uncaught exception ‘NSInternalInconsistencyException’, reason: ‘Text fields can only be added to an alert controller of style UIAlertControllerStyleAlert’
If we do nothing more and present this on an iPhone/compact width device it works as expected:
[self presentViewController:alertController animated:YES completion:nil];

The cancel button, if present, is always shown as the bottom of the view regardless of the order it was added to the alert controller. The other actions are shown top to bottom in the order they were added. The iOS Human Interface Guidelines recommend that any destructive action is shown first.
There is a problem with this code when used on an iPad or regular width device it creates a runtime exception:
Terminating app due to uncaught exception ‘NSGenericException’, reason: ‘UIPopoverPresentationController (<_UIAlertControllerActionSheetRegularPresentationController: 0x7fc619588110>) should have a non-nil sourceView or barButtonItem set before the presentation occurs.’
At the time of writing the Apple UICatalog sample code crashes for the same reason when run on an iPad.
As I mentioned before for regular width presentations the action sheet is displayed in a popover. A popover always requires an anchor point which can be a source view or a bar button item. In this case I am using a standard UIButton to trigger the action sheet so I will use it as the anchor point.
A big difference in iOS 8 is that we no longer need to write code to test for the interface idiom. The UIAlertController takes care of adapting to the display environment so we can simply ask it for a popover controller. On an iPhone/compact width device this returns nil. The extra code we need to configure the popover is below:
UIPopoverPresentationController *popover = alertController.popoverPresentationController;if (popover){popover.sourceView = sender;popover.sourceRect = sender.bounds;popover.permittedArrowDirections = UIPopoverArrowDirectionAny;}
The UIPopoverPresentationController class is also new in iOS 8 and replaces UIPopoverController and for our purposes is functionally equivalent. The action sheet now displays as a popover anchored to the source button:

Note that the UIAlertController is also smart enough to remove the cancel button when using a popover. A user cancels a popover by touching outside of the popover so it is not required.
Dismissing Alert Controllers
Typically the alert controller is dismissed automatically when the user selects an action. It can also be dismissed programmatically, if required, like any other view controller. One common reason can be to remove the alert or action sheet when the app moves to the background. Assuming we are listening for theUIApplicationDidEnterBackgroundNotification notification we can dismiss any presented view controller in the observer (see the example code for the setup of the observer in viewDidLoad):
- (void)didEnterBackground:(NSNotification *)notification{[[NSNotificationCenter defaultCenter] removeObserver:self name:UITextFieldTextDidChangeNotificationobject:nil];[self.presentedViewController dismissViewControllerAnimated:NO completion:nil];}
Note that to be safe we also make sure to remove any text field observers we may have added to the alert controller.
In Summary
A long post but hopefully it will be another three years before I need to write about alert and action sheets again. The old UIAlertView and UIActionSheet classes still work fine in iOS 8 so if you need to target iOS 7 there is no rush to migrate immediately. The AlertController sample Xcode project for this post can be found in my GitHub CodeExamples repository.
UIAlertController Changes in iOS 8的更多相关文章
- IOS开发之IOS8.0最新UIAlertController 分类: ios技术 2015-01-20 14:24 144人阅读 评论(1) 收藏
最近苹果更新的IOS8 对以前进行了很大的修改, 更新的API也让人捉急,据说iOS 8的新特性之一就是让接口更有适应性.更灵活,因此许多视图控制器的实现方式发生了巨大的变化.比如全新的UIPrese ...
- IOS UIAlertController 使用方法
在很多种语言中,alert都表示弹窗操作,弹窗功能非常有用,不仅可以用于正式的app功能中,也可以在调试中使用.在OC中,UIAlertController类用来控制弹窗操作.在IOS 8.0之前, ...
- iOS8 iPad Warning: Attempt to present <UIImagePickerController:xxxx > on xxxx which is already presenting (null)
解决方法: /* I think this is because in iOS 8, alert views and action sheets are actually presented view ...
- 【React Native】在原生和React Native间通信(RN调用原生)
一.从React Native中调用原生方法(原生模块) 原生模块是JS中也可以使用的Objective-C类.一般来说这样的每一个模块的实例都是在每一次通过JS bridge通信时创建的.他们可以导 ...
- iOS UIAlertController跟AlertView用法一样 && otherButtonTitles:(nullable NSString *)otherButtonTitles, ... 写法
今天写弹出框UIAlertController,用alertView习惯了,所以封装了一下,跟alertView用法一样,不说了,直接上代码: 先来了解一下otherButtonTitles:(nul ...
- iOS 8.0后使用UIAlertController
iOS 8的新特性之一就是让接口更有适应性.更灵活,因此许多视图控制器的实现方式发生了巨大的变化.全新的UIPresentationController在实现视图控制器间的过渡动画效果和自适应设备尺寸 ...
- IOS 修改UIAlertController的按钮标题的字体颜色,字号,内容
IOS 修改UIAlertController的按钮标题的字体颜色,字号,内容 UIAlertController *alertVC = [UIAlertController alertControl ...
- iOS UIAlertController
在Xcode的iOS9.0 SDK中,UIAlertView和UIActionSheet都被UIAlertController取代. 在iOS 9中,UIAlertController在功能上是和UI ...
- iOS开发之UIAlertView与UIAlertController的详尽用法说明
本文将从四个方面对IOS开发中UIAlertView与UIAlertController的用法进行讲解: 一.UIAlertView与UIAlertController是什么东东? 二.我们为什么要用 ...
随机推荐
- APUE 学习笔记(九) 高级I/O
1. 非阻塞I/O 低速系统调用时可能会使进程永远阻塞的一类系统调用,包括以下调用: (1)某些文件类型你(网络socket套接字.终端设备.管道)暂无可使用数据,则读操作可能会使调用者永远阻塞 (2 ...
- TroubleShoot: SPD 2013 工作流模板问题解决办法
1. 问题描述: SPD 2013 不能使用2013 工作流模板,在创建过程中,下载更新信息时出现以下错误描述: The server has tried to deliver this messag ...
- 【NOIP2017】逛公园(最短路图,拓扑排序,计数DP)
题意: 策策同学特别喜欢逛公园. 公园可以看成一张 N 个点 M 条边构成的有向图,且没有自环和重边.其中 1 号点是公园的入口, N 号点是公园的出口,每条边有一个非负权值,代表策策经过这条边所要花 ...
- C++拷贝(复制)构造函数详解
原文:http://blog.csdn.net/lwbeyond/article/details/6202256/[侵删] 一. 什么是拷贝构造函数 首先对于普通类型的对象来说,它们之间的复制是很简单 ...
- C++ 细节知识
1.typedef struct child {string name;struct child* next;}; child* head; head = (child*)malloc(sizeof( ...
- 推荐!手把手教你使用Git(转)
原文出处: 涂根华的博客 欢迎分享原创到伯乐头条 一:Git是什么? Git是目前世界上最先进的分布式版本控制系统. 二:SVN与Git的最主要的区别? SVN是集中式版本控制系统,版本库是集中放 ...
- html移动端 -- meta-模板 + rem
第一种方式: ps 不用除以2<header> <meta charset="utf-8"> <meta name="viewport&qu ...
- 信息收集渠道:文本分享类网站Paste Site
信息收集渠道:文本分享类网站Paste Site Paste Site是一种专门的文本分享的网站.用户可以将一段文本性质的内容(如代码)上传到网站,然后通过链接分享给其他用户.这一点很类似于现在的优酷 ...
- shell-异步执行
一.启动后台子任务 在执行命令后加&操作符,表示将命令放在子shell中异步执行.可以达到多线程效果.如下, sleep 10 #等待10秒,再继续下一操作 sleep 10 & #当 ...
- ConcurrentHashMap如何保证线程安全
以前看过HashMap的内部实现,知道HashMap是使用Node数组+链表+红黑树的数据结构来实现,如下图所示.但是HashMap是非线程安全,在多线程环境不能够使用. 不过JDK在其并发包中为我们 ...