美文网首页
Runtime笔记二:关联对象Associated Object

Runtime笔记二:关联对象Associated Object

作者: 蔚尼 | 来源:发表于2018-05-23 17:17 被阅读7次

    因为需要用到分类,可以先看这篇文章小小的复习一下分类。https://www.jianshu.com/p/bb85e01fdbeb

    一.关联对象

    1.关联对象的作用:

    关联对象(Associated Object)可以给分类(category)添加属性。

    2.关联对象的API

    //关联对象
    void objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy)
    //获取关联的对象
    id objc_getAssociatedObject(id object, const void *key)
    //移除关联的对象
    void objc_removeAssociatedObjects(id object)
    
    • id objec :被关联对象
    • key :关联的key(用于获取和设置关联对象)
    • value :关联的对象
    • objc_AssociationPolicy policy:内存关联策略

    二.实例演示

    1.为分类添加属性

    .h类:
    @interface NSObject (AssociatedObject)
    
    //为分类添加属性associatedObject
    @property(nonatomic,strong)id associatedObject;
    
    @end
    
    .m类:
    #import "NSObject+AssociatedObject.h"
    #import <objc/runtime.h>
    
    @implementation NSObject (AssociatedObject)
    
    //添加set方法
    -(void)setAssociatedObject:(id)associatedObject{
    
        objc_setAssociatedObject(self, @selector(associatedObject), associatedObject, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
     /*
         当宿主对象被释放时,会根据指定的内存管理策略来处理关联对象。
         如果指定的策略是assign,则宿主释放时,关联对象不会被释放;
         而如果指定的是retain或者是copy,则宿主释放时,关联对象会被释放。
         我们甚至可以选择是否是自动retain/copy。当我们需要在多个线程中处理访问关联对象的多线程代码时,这就非常有用了。
    
         objc_AssociationPolicy                 modifier
         OBJC_ASSOCIATION_ASSIGN                assign
         OBJC_ASSOCIATION_RETAIN_NONATOMIC      nonatomic, strong
         OBJC_ASSOCIATION_COPY_NONATOMIC        nonatomic, copy
         OBJC_ASSOCIATION_RETAIN                atomic, strong
         OBJC_ASSOCIATION_COPY                  atomic, copy
    
    
    
         */
    }
    
    //添加get方法
    -(id)associatedObject{
    
        return objc_getAssociatedObject(self, _cmd);
        //cmd 代指当前方法的选择子,也就是 @selector(categoryProperty)。_cmd在Objective-C的方法中表示当前方法的selector,正如同self表示当前方法调用的对象实例。这里强调当前,_cmd的作用域只在当前方法里,直指当前方法名@selector
    
        //或者写成:
       //return objc_getAssociatedObject(self, @selector(associatedObject));
    
    }
    @end
    
    viewcontroller使用:
    #import "NSObject+AssociatedObject.h"
    @implementation ViewController
    
    //为分类添加属性
    -(void)addPropertyForCategory{
        NSObject * associateObj = [[NSObject alloc] init];
        associateObj.associatedObject = @"associatedObject";
        NSLog(@"%@",associateObj.associatedObject);//成功获取并打印
    }
    @end
    

    1.可以用到给手势的分类添加一个字符串,手势获取的时候取到相关信息
    2.我们实现的只是getter和setter方法,并没有自动生成下划线开头的变量!

    2.为UI控件关联block体/为分类添加block属性

    为AlertView分类添加block,点击alertview的“确定”、“取消”时调用block

    .h类:
    //定义block
    typedef void (^ClickBlock)(NSInteger btnIndex);
    
    @interface UIAlertView (Handle)
    
    @property(nonatomic,copy)ClickBlock clickBlock;
    
    @end
    
    .m类:
    #import "UIAlertView+Handle.h"
    #import <objc/runtime.h>
    
    @implementation UIAlertView (Handle)
    //添加set方法
    -(void)setClickBlock:(ClickBlock)clickBlock{
        
        objc_setAssociatedObject(self, @selector(clickBlock), clickBlock, OBJC_ASSOCIATION_COPY_NONATOMIC);
    }
    
    //添加get方法
    -(ClickBlock)clickBlock{
        
        return objc_getAssociatedObject(self, _cmd);
        
    }
    @end
    
    viewcontroller使用
    //关联block体
    -(void)addBlock{
        
        UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Question" message:@"What do you want to do?" delegate:self cancelButtonTitle:@"Cancel" otherButtonTitles:@"Continue", nil];
        //设置分类添加的block属性
        [alert setClickBlock:^(NSInteger btnIndex) {
            if (btnIndex == 0) {
                NSLog(@"cancel");
            }else{
                NSLog(@"continue");
            }
    
        }];
        [alert show];
    }
    -(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex{
      
        //调用分类里面的block属性,点击alertview的“确定”、“取消”时调用新增的block
        void (^clickBlock)(NSInteger) = alertView.clickBlock;
        clickBlock(buttonIndex);
     
    }
    

    3.使用分类里面的block实现Button的点击方法

    和上面的方法相比,增加:

    1. 使用非set方法来关联对象;
    2. 把block的调用放到了分类里面;

    我们现在为button增加一个分类,定义一个block方法,点击按钮的时候我们调用这个block处理事件

    .h类:
    #import <UIKit/UIKit.h>
    //定义block
    typedef void(^BtnClickCallBack)(UIButton *);
    
    @interface UIButton (Handle)
    
    //使用一个方法(非set方法)来关联对象,也方便外面调用
    -(void)handleClickCallBack:(BtnClickCallBack)callBack;
    
    @end
    
    .m类:
    #import "UIButton+Handle.h"
    #import <objc/runtime.h>
    
    static const char * BtnCall = "btnCall";
    
    @implementation UIButton (Handle)
    
    //使用一个方法(非set方法)来关联对象,也方便外面调用
    -(void)handleClickCallBack:(BtnClickCallBack)callBack{
        
        //a、关联block
        objc_setAssociatedObject(self, BtnCall, callBack, OBJC_ASSOCIATION_COPY_NONATOMIC);
        //b、设置btn执行的方法
        [self addTarget:self action:@selector(btnClick) forControlEvents:UIControlEventTouchUpInside];
        
        //做了a、b两步之后,使用的地方调用handleClickCallBack方法,即关联了block,也可以增加点击事件
    }
    
    -(void)btnClick{
        
        //取出关联的block,调用block
        BtnClickCallBack callBack = objc_getAssociatedObject(self, BtnCall);
        if (callBack) {
            callBack(self);
        }
    }
    @end
    
    viewcontroller使用:
    
        UIButton * testBtn = [UIButton buttonWithType:UIButtonTypeCustom];
        testBtn.frame = CGRectMake(100, 100, 50, 50);
        [testBtn setBackgroundColor:[UIColor redColor]];
        [self.view addSubview:testBtn];
        
        [testBtn handleClickCallBack:^(UIButton * btn) {//点击testBtn的时候就会调用block
            NSLog(@"testbtn的事件");
        }];
    

    总结:
    使用关联对象可以给分类添加属性、添加block属性;可以通过get、set方法来设置和获取属性的值;也可以通过添加利于使用时候调用的方法来设置和获取属性的值。

    相关文章

      网友评论

          本文标题:Runtime笔记二:关联对象Associated Object

          本文链接:https://www.haomeiwen.com/subject/adnrjftx.html