简单的封装UIAlertView、UIActionSheet、UIAlertController、KVO。封装之后不使用代理,使用block直接调用响应事件。
直接提供Demo地址:SimpleBlock
1、UIAlertView 封装
1、 静态方法Block实现。
typedef void (^ClickAtIndexBlock)(NSInteger buttonIndex);
@interface KAlertView : NSObject <UIAlertViewDelegate>
+ (UIAlertView *)initWithTitle:(NSString *)title
message:(NSString *)messge
cancleButtonTitle:(NSString *)cancleButtonTitle
OtherButtonsArray:(NSArray *)otherButtons
clickAtIndex:(ClickAtIndexBlock)clickAtIndex;
@end
初始化方法,加一个Block。
static ClickAtIndexBlock _ClickAtIndexBlock;
@implementation KAlertView
+ (UIAlertView *)initWithTitle:(NSString *)title
message:(NSString *)messge
cancleButtonTitle:(NSString *)cancleButtonTitle
OtherButtonsArray:(NSArray *)otherButtons
clickAtIndex:(ClickAtIndexBlock)clickAtIndex {
_ClickAtIndexBlock = [clickAtIndex copy];
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:title
message:messge
delegate:self
cancelButtonTitle:cancleButtonTitle
otherButtonTitles: nil];
for (NSString *otherTitle in otherButtons) {
[alertView addButtonWithTitle:otherTitle];
}
[alertView show];
return alertView;
}
#pragma mark UIAlertViewDelegate
+ (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
_ClickAtIndexBlock(buttonIndex);
}
+ (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex {
_ClickAtIndexBlock = nil;
}
@end
注解:
我们这里的UIAlertView代理不是给的类对象,而是给的类本身,而类本身也是对象,是元类的对象,所以代理方法也要改成类本身的代理方法,方能执行。
UIAlertView的封装就完成了,调用的时候我们就可以相对简单一点了。
[KAlertView initWithTitle:@"title" message:@"message" cancleButtonTitle:@"cancle" OtherButtonsArray:@[@"sure",@"very"] clickAtIndex:^(NSInteger buttonIndex) {
NSLog(@"--index : %ld",buttonIndex);
}];
1、 Runtime Block实现。
@interface KRAlertView : NSObject <UIAlertViewDelegate>
typedef void (^ClickAtIndexBlock)(NSInteger buttonIndex);
+ (UIAlertView *)initWithTitle:(NSString*)title
message:(NSString *)messge
cancleButtonTitle:(NSString *)cancleButtonTitle
OtherButtonsArray:(NSArray*)otherButtons
clickAtIndex:(ClickAtIndexBlock) clickAtIndex;
@end
和第一个实现方法一样,加一个block 一个初始化
#import <objc/runtime.h>
const char *KUIAlertView_runtime_key = "KUIAlertView_runtime_key";
@interface UIAlertView (KRAlertView)
- (void)setClickBlock:(ClickAtIndexBlock)block;
- (ClickAtIndexBlock)clickBlock;
@end
@implementation UIAlertView(KRAlertView)
- (void)setClickBlock:(ClickAtIndexBlock)block {
objc_setAssociatedObject(self, KUIAlertView_runtime_key, block, OBJC_ASSOCIATION_COPY);
}
- (ClickAtIndexBlock)clickBlock {
return objc_getAssociatedObject(self, KUIAlertView_runtime_key);
}
@end
@implementation KRAlertView
+ (UIAlertView *)initWithTitle:(NSString*)title
message:(NSString *)messge
cancleButtonTitle:(NSString *)cancleButtonTitle
OtherButtonsArray:(NSArray*)otherButtons
clickAtIndex:(ClickAtIndexBlock) clickAtIndex {
UIAlertView *alerView = [[UIAlertView alloc] initWithTitle:title message:messge delegate:self cancelButtonTitle:cancleButtonTitle otherButtonTitles: nil];
alerView.clickBlock = clickAtIndex;
for (NSString *otherTitle in otherButtons) {
[alerView addButtonWithTitle:otherTitle];
}
[alerView show];
return alerView;
}
#pragma mark UIAlertViewDelegate
+ (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
if (alertView.clickBlock) {
alertView.clickBlock(buttonIndex);
}
}
实际上runtime实现的主要思想就是给UIAlertView的类别加一个block属性。然后就可以直接使用这个属性,从而调用block。
这里面的主要思想是runtime的关联属性
objc_setAssociatedObject(self, KUIAlertView_runtime_key, block, OBJC_ASSOCIATION_COPY);
将某个值跟某个对象关联起来,将某个值存储到某个对象中
// 第一个参数:给哪个对象添加属性
// 第二个参数:属性名称
// 第三个参数:属性值
// 第四个参数:保存策略
objc_getAssociatedObject(self, KUIAlertView_runtime_key);
获取相应对象的关联值。
调用和第一种方法相同。
2、UIActionSheet 封装
UIActionSheet 实现方法和UIAlertView相同,但是这里提供一个不需要静态方法,使用runtime的实现方式。首先创建一个类别,具体代码如下。
typedef void (^ClickAtIndexBlock)(NSInteger buttonIndex);
@interface UIActionSheet (block)
- (void)showActionSheetInView:(UIView *)showView clickCompleteBlock:(ClickAtIndexBlock)block;
@end
#import <objc/runtime.h>
static void *key = "KActionSheet_runtime_key";
@implementation UIActionSheet (block)
- (void)showActionSheetInView:(UIView *)showView clickCompleteBlock:(ClickAtIndexBlock)block {
if (block) {
objc_removeAssociatedObjects(self);
objc_setAssociatedObject(self, key, block, OBJC_ASSOCIATION_COPY);
self.delegate = (id<UIActionSheetDelegate>)self;
}
[self showInView:showView];
}
#pragma mark UIActionSheetDelegate
- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex {
ClickAtIndexBlock block = objc_getAssociatedObject(self, key);
if (block) {
block(buttonIndex);
}
}
@end
原理类似,只是这种方法调用相对其他两种方法多一句话如下
UIActionSheet *actionSheet = [[UIActionSheet alloc] initWithTitle:@"title" delegate:nil cancelButtonTitle:@"cancel" destructiveButtonTitle:nil otherButtonTitles:@"1",@"2", nil];
[actionSheet showActionSheetInView:self.view clickCompleteBlock:^(NSInteger buttonIndex) {
NSLog(@"--- %ld",buttonIndex);
}];
3、UIAlertController 封装
ios8之后不是推荐使用这个控件吗,当然这个功能相对比UIAlertView和UIActionSheet要强大,所以我也就稍微封装一下。这个封装就没有runtime,也没有使用类对象了,直接上代码。
#import <UIKit/UIKit.h>
typedef void (^ClickAlertBlock)(NSString *title);
@interface KAlertController : NSObject
+ (UIAlertController *)showAlertWith:(UIViewController *)showController
title:(NSString *)title
message:(NSString *)message
cancleTitle:(NSString *)cancleTitle
actionTitle:(NSArray *)titleArrary
alertType:(UIAlertControllerStyle)alerType
andClickAlertBlock:(ClickAlertBlock)block;
@end
@implementation KAlertController
+ (UIAlertController *)showAlertWith:(UIViewController *)showController
title:(NSString *)title
message:(NSString *)message
cancleTitle:(NSString *)cancleTitle
actionTitle:(NSArray *)titleArrary
alertType:(UIAlertControllerStyle)alerType
andClickAlertBlock:(ClickAlertBlock)block {
UIAlertController *alertController = [UIAlertController alertControllerWithTitle:title message:message preferredStyle:alerType];
for (NSString *actionTitle in titleArrary) {
UIAlertAction *action = [UIAlertAction actionWithTitle:actionTitle style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
if (block) {
block(actionTitle);
}
}];
[alertController addAction:action];
}
UIAlertAction *action = [UIAlertAction actionWithTitle:cancleTitle style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
if (block) {
block(cancleTitle);
}
}];
[alertController addAction:action];
[showController presentViewController:alertController animated:YES completion:nil];
return alertController;
}
@end
调用也是一句话,根据枚举调用出来你想要的,这里只举例UIAlertVIew
[KAlertController showAlertWith:self
title:@"title"
message:@"message"
cancleTitle:@"cancle"
actionTitle:@[@"1",@"2"]
alertType:UIAlertControllerStyleAlert
andClickAlertBlock:^(NSString *title) {
NSLog(@"title :%@",title);
}];
4、KVO Block调用
原理和以上类似,只需要加一个NSObject类别
typedef void (^CompleteChangeBlock)(id _Nonnull obj, id _Nonnull oldVal, id _Nonnull newVal);
@interface NSObject (KVO)
- (void)addObserver:(NSObject *_Nullable)observer
forKeyPath:(NSString *_Nullable)keyPath
completeChangeBlock:(CompleteChangeBlock _Nullable )block;
@end
static CompleteChangeBlock _CompleteChangeBlock;
@implementation NSObject (KVO)
- (void)addObserver:(NSObject *_Nullable)observer
forKeyPath:(NSString *_Nullable)keyPath
completeChangeBlock:(CompleteChangeBlock _Nullable )block {
_CompleteChangeBlock = block;
[self addObserver:observer forKeyPath:keyPath options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:nil];
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)contextt {
if (_CompleteChangeBlock) {
_CompleteChangeBlock(object,change[@"old"],change[@"new"]);
}
}
@end
调用:
[self addObserver:self forKeyPath:@"number" completeChangeBlock:^(id _Nonnull obj, id _Nonnull oldVal, id _Nonnull newVal) {
NSLog(@"obj :%@ old: %@ new: %@",obj,oldVal,newVal);
}];