iOS8之UIAlertController

由起

UIAlertController是iOS8中引入的,用于整合UIAlertViewUIActionSheet的新类,在实现中抛弃了之前的delegate用法,而采用了block的方式,从而使得使用和可读性都简化了不少。
使用iOS8SDK编译的项目,大多数情况使用之前的UIAlertViewUIActionSheet都不会产生问题,如果有问题了,那就需要使用新类了。比如,一个项目中iPad上调用[actionSheet showFromToolbar:]产生错误:

2014-11-05 10:50:26.614 XXXXXX[467:78104] Presenting view controllers on detached view controllers is discouraged <UIViewController: 0x17ea3470>.
2014-11-05 10:50:26.762 XXXXXX[467:78104] *** Terminating app due to uncaught exception 'NSGenericException', reason: 'Your application has presented a UIAlertController (<UIAlertController: 0x17e73620>) 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.'

从奔溃日志中可以看出,虽然代码中使用的是UIActionSheet,实际运行时却已经是UIAlertController了。

使用

使用非常简单,基本用法:

//初始化alert controller
UIAlertController *alertController = [UIAlertController alertControllerWithTitle:ZJLocalizedString(@"xxxx") message:nil preferredStyle:UIAlertControllerStyleActionSheet];
//创建一个操作
UIAlertAction *fileAction = [UIAlertAction actionWithTitle:ZJLocalizedString(@"action1") style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
        [self doAction1];
    }];
//添加操作
[alertController addAction:fileAction];
//
UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:ZJLocalizedString(@"Cancel") style:UIAlertActionStyleCancel handler:^(UIAlertAction *action) {

    }];
[alertController addAction:cancelAction];

//展示alert controller   
[self presentViewController:alertController animated:YES completion:^{

    }];

初始化controller的时候,通过UIAlertActionStyle来选择哪种式样,然后就创建一系列action,并添加到controller,最后把controller用present的方式展示出来。对于以前alert上带文字的式样,新API也贴心的提供了addTextFieldWithConfigurationHandler:(void (^)(UITextField *textField))configurationHandler方法来简化操作。

可见,新API最大的特点无疑就是吸取了开源社区中已有的block的实现,这样最大限度的简化了代码,并且带来了无与伦比的可读性。由于新API中action的初始化是类方法,如果action不作为类成员的话,也不需要考虑block的循环引用问题。

结束

iOS8对API的更新还是挺大的,比如UIPopoverViewController兼容iPad和iPhone,所以可以慢慢的开始更新了。

紧急修正

经过测试,在ipad上的使用还需要注意一个问题,那就是在present之前要设置UIAlertController的属性popoverPresentationController。该属性是UIPopoverPresentationController类,主要用途就是管理popover中的内容。如果不设置,在iPad竖屏测试的时候没有问题,但是在横屏的时候就会有问题。原因在于,横屏的时候,popover没有指定位置。这时,可以

UIPopoverPresentationController *popoverPresentationController = alertController.popoverPresentationController;        
popoverPresentationController.barButtonItem = (UIBarButtonItem *)sender;
//或
popoverPresentationController.sourceView = (UIButton *)sender;
popoverPresentationController.sourceRect = [(UIButton *)sender bounds];

Comments