首页 为类关联对象
文章
取消

为类关联对象

相信大家多多少少都见过objc_setAssociatedObjectobjc_getAssociatedObject这两个方法。

它们到底有什么用呢?如果只是说关联对象,这好像也没体现出来具体的作用,下面我来说一个比较实际作用。 在使用UIAlertView的时候有没有觉得很麻烦,点击按钮的逻辑处理必须写在协议方法中,如果一个VC中存在多个UIAlertView就会更复杂,这样就必须在协议方法中判断传入alertView对象。我们可以利用上述两个方法一劳永逸的解决类似问题

最终得到创建和显示一个UIAlertView将会是这样子的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
	[self showAlertViewWithTitle:@"是否确定结案"
                             message:nil
                   cancelButtonTitle:@"取消"
                   otherButtonTitles:@[@"退回", @"接收"]
                            onCancel:^{  
            NSLog(@"取消按钮点击");
        }onOther:^(NSInteger index) {
            if (index == 0) {
                NSLog(@"其他第一个按钮点击");
            }
            else{
                NSLog(@"其他第二个按钮点击");
            }
        }];

可以看到在创建UIAlertView的时候已经把每个按钮要处理的逻辑都写好了。

下面开始动手写这个扩展,我们创建一个名叫AddonsUIViewController扩展

UIViewController+Addons.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#import <Foundation/Foundation.h>
typedef void(^HandleBlock)(void);
typedef void(^OtherHandleBlock)(NSInteger index);
@interface UIViewController(Addons)<UIAlertViewDelegate>
/**
 *  显示alterView
 *
 *  @param title             title
 *  @param message           message
 *  @param cancelButtonTitle 取消按钮的title
 *  @param otherButtonTitles otherButton的title数组
 *  @param cancelBlock       取消按钮执行的block
 *  @param otherBlock        other按钮执行的block
 */
- (void)showAlertViewWithTitle:(NSString *) title
                      message:(NSString *) message
            cancelButtonTitle:(NSString *) cancelButtonTitle
            otherButtonTitles:(NSArray *) otherButtonTitles
                     onCancel:(CancelBlock) cancelBlock
                      onOther:(OtherHandleBlock) otherBlock;

typedef两个block,第一个用于点击取消按钮执行,第二个用于点击其他按钮执行,因为其他按钮可能有多个,所以加入了index参数来判断点击的是哪个按钮。

UIViewController+Addons.m

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#import "UIViewController+Addons.h"
#import <objc/runtime.h>
static char kVCActionHandleAlertCancelBlockKey;
static char kVCActionHandleAlertOtherBlockKey;
@implementation UIViewController(Addons)
-(void)showAlertViewWithTitle:(NSString *)title
                      message:(NSString *)message
            cancelButtonTitle:(NSString *)cancelButtonTitle
            otherButtonTitles:(NSArray *)otherButtonTitles
                     onCancel:(CancelBlock)cancelBlock
                      onOther:(OtherHandleBlock)otherBlock{
     UIAlertView *alertView = [[UIAlertView alloc]initWithTitle:title
                                                       message:message
                                                      delegate:self
                      	                   cancelButtonTitle:cancelButtonTitle
                                             otherButtonTitles:nil];
    for(NSString *buttonTitle in otherButtonTitles){
        [alertView addButtonWithTitle:buttonTitle];
    }
    if (cancelBlock) {
        objc_setAssociatedObject(self, &kVCActionHandleAlertCancelBlockKey, cancelBlock, OBJC_ASSOCIATION_COPY_NONATOMIC);
    }
    if (otherBlock) {
        objc_setAssociatedObject(self, &kVCActionHandleAlertOtherBlockKey, otherBlock, OBJC_ASSOCIATION_COPY_NONATOMIC);
    }
    [alertView show];
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
-(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex{
	if(buttonIndex == alertView.cancelButtonIndex){
        CancelBlock cancelBlock = objc_getAssociatedObject(self, &kVCActionHandleAlertCancelBlockKey);
        if(cancelBlock){
            cancelBlock();
        }
    }
    else{
        OtherHandleBlock otherBlock = objc_getAssociatedObject(self, &kVCActionHandleAlertOtherBlockKey);
        if(otherBlock){
            otherBlock(buttonIndex - 1);
        }
    }
}

记得导入<objc/runtime.h>头文件,创建UIAlertView,然后把传入的两个block关联到UIViewController对象上,也就是这步

1
2
3
4
5
6
7
 if (cancelBlock) {
        objc_setAssociatedObject(self, &kVCActionHandleAlertCancelBlockKey, cancelBlock, OBJC_ASSOCIATION_COPY_NONATOMIC);
    }
    if (otherBlock) {
        objc_setAssociatedObject(self, &kVCActionHandleAlertOtherBlockKey, otherBlock, OBJC_ASSOCIATION_COPY_NONATOMIC);
    }

需要注意的是这里关联的规则最好用OBJC_ASSOCIATION_COPY_NONATOMIC,以便让ARC来管理这个block。后面的协议方法也就是把blockself中取出来执行。

当然还有UIActionSheet甚至UIImagePickerController也可以这样来扩展

本文由作者按照 CC BY 4.0 进行授权

NSCountedSet

Masonry