- Notifications
You must be signed in to change notification settings - Fork0
【iOS】深度封装UIAlertController,良好兼容UIAlertControllerStyleAlert和UIAlertControllerStyleActionSheet
License
XiFengLang/JKAlertManager
Folders and files
Name | Name | Last commit message | Last commit date | |
---|---|---|---|---|
Repository files navigation
JKAlertManager是基于UIAlertController封装的管理类,将UIAlertController分散的ActionBlcok集中到一个Blcok中,并且实现主动释放的Block,内存管理更安全,代码精简高效。
platform :ios,'8.0'source'https://github.com/CocoaPods/Specs.git'pod 'JKAlertManager', '~>1.2.1'
- JKAlertManager简介
- JKAlertManager迭代记录
- JKAlertManager用法
- JKAlertManager部分代码用意介绍
- 快速替换掉工程中所有的UIAlertView
- 封装UIAlertView、UIActionSheet的Block分类,替换代理方法
- 基于UIAlertController封装,兼容UIAlertControllerStyleAlert和UIAlertControllerStyleActionSheet
- UIAlertControllerStyleActionSheet类型兼容了iPad中的PopoverController
- 主动释放Block,内存管理更安全,有效规避Block循环引用
- 支持监听多个UITextField的文字内容变化,并通过Block回调监听结果
- 1.0.4,增加JKAlertView类用于全局替换UIAlertView。
- 1.1.0,JKAlertManager继承NSObject, 不再继承UIView。
JKAlertManager * manager = [[JKAlertManager alloc] initWithPreferredStyle:UIAlertControllerStyleAlert title:<#title#> message:<#nil#>]; [manager configueCancelTitle:<#@"取消"#> destructiveIndex:JKAlertDestructiveIndexNone otherTitles:<#array#>]; [manager showAlertFromController:self actionBlock:^(JKAlertManager *tempAlertManager, NSInteger actionIndex, NSString *actionTitle) { if (actionIndex != tempAlertManager.cancelIndex) { <#doSomething#> } }];
JKAlertManager * manager = [[JKAlertManager alloc]initWithPreferredStyle:UIAlertControllerStyleAlert title:self.dataArray[indexPath.row] message:self.dataArray[indexPath.row] ];[manager configueCancelTitle:@"取消" destructiveIndex:1 otherTitles:@"其他按钮1",@"Destructive按钮",@"其他按钮2", nil];[manager addTextFieldWithPlaceholder:@"请输入账号" secureTextEntry:NO ConfigurationHandler:nil textFieldTextChanged:^(UITextField *textField) { NSLog(@"1 %@",textField.text);}];[manager addTextFieldWithPlaceholder:@"请输入密码" secureTextEntry:YES ConfigurationHandler:^(UITextField *textField) { textField.clearsOnBeginEditing = YES;} textFieldTextChanged:^(UITextField *textField) { NSLog(@"2 %@",textField.text);}]; [manager showAlertFromController:self actionBlock:^(JKAlertManager *tempAlertManager, NSInteger actionIndex, NSString *actionTitle) { UITextField * userNameTextField = tempAlertManager.textFields[0]; UITextField * passwordTextField = tempAlertManager.textFields[1]; }];
如果App支持iPad,需调用configuePopoverControllerForActionSheetStyleWithSourceView:
适配iPad。
JKAlertManager * manager = [[JKAlertManager alloc]initWithPreferredStyle:UIAlertControllerStyleActionSheet title:@"title" message:@"massage" ];[manager configueCancelTitle:nil destructiveIndex:0 otherTitles:@"Destructive按钮",@"其他按钮1",@"其他按钮2", nil];[manager configuePopoverControllerForActionSheetStyleWithSourceView:cell sourceRect:cell.bounds popoverArrowDirection:UIPopoverArrowDirectionAny];[manager showAlertFromController:self actionBlock:^(JKAlertManager *tempAlertManager, NSInteger actionIndex, NSString *actionTitle) { self...}];
之前封装的难点主要在于拆分
(NSString *)otherTitle, ...NS_REQUIRES_NIL_TERMINATION
,将otherTitle转换成数组,用法见Demo或者NS_REQUIRES_NIL_TERMINATION。但后来发现并没啥优越性,可以直接传NSArray。解除Block循环引用的思路参考了AFNetworking
,即调用了Block后,再将Block = nil置空,即可解除循环引用,这种思路只适合调用一次的Block,多次调用的Block还是需要进行self强弱转换。1.1.0
版中,JKAlertManager 改成继承 NSObject,被内部__JKAlertManagerPrivateHolder
类私有View强引用,JKAlertManager则会弱引用这个私有View。详情请看下面的代码:
@interface __JKAlertManagerPrivateHolder : UIView@property (nonatomic, strong) JKAlertManager * alertManager;@end@implementation __JKAlertManagerPrivateHolder@end@interface JKAlertManager ()@property (nonatomic, weak) __JKAlertManagerPrivateHolder * privateHolder;@end
私有ViewprivateHolder
在showAlertFromController:(UIViewController *)ViewController
方法中添加到控制器ViewController.view上,间接实现控制器对JKAlertManager的强引用。privateHolder
调用removeFromSuperView
来解除强引用,破坏原来的引用链,从而实现自释放。
- (void)showAlertFromController:(UIViewController *)controller actionBlock:(JKAlertActionBlock)actionBlock{ if (self.privateHolder) { [self.privateHolder removeFromSuperview]; self.privateHolder = nil; } /// 私有类,强引用JKAlertManager __JKAlertManagerPrivateHolder * privateHolder = [[__JKAlertManagerPrivateHolder alloc] initWithFrame:CGRectZero]; privateHolder.backgroundColor = [UIColor clearColor]; privateHolder.alertManager = self; self.privateHolder = privateHolder; [controller.view addSubview:privateHolder]; [controller presentViewController:self.alertController animated:YES completion:nil]; // 解除Block循环引用,释放内存 __weak typeof(self) weakSelf = self; self.privateBlock = ^(NSInteger actionIndex, NSString * actionTitle){ __strong typeof(weakSelf) strongSelf = weakSelf; if (actionBlock) actionBlock(strongSelf, actionIndex, actionTitle); [[NSNotificationCenter defaultCenter]removeObserver:strongSelf]; strongSelf.alertController = nil; strongSelf.otherTitles = nil; /// 主动释放Block,解除循环引用 [strongSelf.privateHolder removeFromSuperview]; strongSelf.textFieldChangedBlockMutDict = nil; strongSelf.privateBlock = nil; };}
如果项目中用到的UIAlertView相当多,同时又想全部换成UIAlertController,可用JKAlertView全局替换UIAlertView,大部分的UIAlertView都能替换,同时不用改原来的逻辑代码和代理方法。现在UIAlertView使用过程中并无异常,所以替不替换都无所谓。如果不需要全局替换UIAlertView,JKAlertView可删除掉,详情请查看工程中ReplaceViewController.m
文件中的代码。
#import "JKAlertView.h"
同时按
Command + Option + Shift + F
组合键`,用JKAlertView全局替换UIAlertView
- 一个UIAlertView或UIActionSheet对象对应一个Block,代码紧凑。
- 实现Block主动释放,规避Block循环引用,不会出现内存泄露。
如果控制器使用到多个UIAlertView或者UIActionSheet
,那么需要在多个地方创建对象并设置delegate和tag
,然后集中在一个代理方法中先根据tag区分对象,再区分buttonIndex
,这样写的代码比较分散,可读性不强。封装后的UIAlertView或者UIActionSheet
使用代码可读性更强,代码更紧凑。
不建议使用strong修饰alertView或者actionSheet属性,如果非得用属性,建议使用weak。
@property (nonatomic, strong)UIAlertView * alertView;@property (nonatomic, strong)UIActionSheet * actionSheet;
self.alertView = [[UIAlertView alloc]initWithTitle:@"title" message:@"message" delegate:nil cancelButtonTitle:@"取消" otherButtonTitles:@"其他", nil]; [self.alertView showAlertViewWithActionBlock:^(UIAlertView *newAlertView, NSInteger buttonIndex) { self... }]; self.actionSheet = [[UIActionSheet alloc]initWithTitle:@"title" delegate:nil cancelButtonTitle:@"取消" destructiveButtonTitle:@"destructiveButtonTitle" otherButtonTitles:@"otherButtonTitles", nil]; [self.actionSheet showActionSheetInView:self.view completion:^(UIActionSheet *originalActionSheet, NSInteger buttonIndex) { self... }];
About
【iOS】深度封装UIAlertController,良好兼容UIAlertControllerStyleAlert和UIAlertControllerStyleActionSheet
Topics
Resources
License
Uh oh!
There was an error while loading.Please reload this page.