iOS 中runtime特性之关联属性

/ 0评 / 0

关联是指把两个对象相互关联起来,使得其中的一个对象作为另外一个对象的一部分。就是说一个对象可以保持对另一个对象的引用,并获取那个对象。有了这些,就能实现属性功能了。

这是iOS中运行时的特性,所以首先要导入 #import 头文件 ,来看一下关联中要用到的方法

typedef OBJC_ENUM(uintptr_t, objc_AssociationPolicy) {
    OBJC_ASSOCIATION_ASSIGN = 0,   //表示弱引用关联,通常是基本数据类型,如int、float
    OBJC_ASSOCIATION_RETAIN_NONATOMIC = 1,  //表示强(strong)引用关联对象
    OBJC_ASSOCIATION_COPY_NONATOMIC = 3,    //表示关联对象copy
    OBJC_ASSOCIATION_RETAIN = 01401,      //表示强(strong)引用关联对象,但不是线程安全的
    OBJC_ASSOCIATION_COPY = 01403         //表示关联对象copy,但不是线程安全的
};

/**
设置关联,需要使用下面的API关联起来
object:与谁关联,通常是传self
key:唯一键,在获取值时通过该键获取,通常是使用static const void *来声明
value:关联所设置的值
policy:内存管理策略,比如使用copy
**/

OBJC_EXPORT void objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy)
    __OSX_AVAILABLE_STARTING(__MAC_10_6, __IPHONE_3_1);

/**
获取所关联的值,需要通过key来获取
object:与谁关联,通常是传self,在设置关联时所指定的与哪个对象关联的那个对象
key:唯一键,在设置关联时所指定的键
**/

OBJC_EXPORT id objc_getAssociatedObject(id object, const void *key)
    __OSX_AVAILABLE_STARTING(__MAC_10_6, __IPHONE_3_1);


//这个我们几乎不会用到,因为他会断开所有关联。只有在需要把对象恢复到“原始状态”的时候才会使用这个函数。
OBJC_EXPORT void objc_removeAssociatedObjects(id object)
    __OSX_AVAILABLE_STARTING(__MAC_10_6, __IPHONE_3_1);

我们来看一个例子

    static char overviewKey;
    NSArray *array = [[NSArray alloc] initWithObjects:@"测试1",@"测试2",@"测试3", nil];
    NSString *overview = @"浮点数";
    
    //设置关联
    objc_setAssociatedObject(array, &overviewKey, overview, OBJC_ASSOCIATION_RETAIN);
    
    //取出关联值
    NSString *associatedObject = (NSString *)objc_getAssociatedObject(array, &overviewKey);
    
    NSLog(@"%@",associatedObject);
    
   
    //断开关联
    objc_setAssociatedObject(array, &overviewKey, nil, OBJC_ASSOCIATION_ASSIGN);

用起来还是比较简单的,那下面我们就可以给其他的控件添加操作了,我们这里给UIControl添加一个block

    typedef void (^DCTouchUpBlock)(id sender);
    @interface UIControl (DCControl)
    @property (nonatomic, copy) DCTouchUpBlock dc_touchUpBlock;
    @end

     
     #import 
     static const void *kDCTouchUpBlockKey = "kDCTouchUpBlockKey";
     @implementation UIControl (DCControl)

	- (void)setDc_touchUpBlock:(DCTouchUpBlock)dc_touchUpBlock{
	    objc_setAssociatedObject(self,
	                             kDCTouchUpBlockKey,
	                             dc_touchUpBlock,
	                             OBJC_ASSOCIATION_COPY);
	    
	    
	    [self removeTarget:self
	                action:@selector(dcOnTouchUp:)
	                forControlEvents:UIControlEventTouchUpInside];
	    
	    if (dc_touchUpBlock) {
	        [self addTarget:self
	                 action:@selector(dcOnTouchUp:)
	                 forControlEvents:UIControlEventTouchUpInside];
	    }
	}

	- (DCTouchUpBlock)dc_touchUpBlock {
	    return objc_getAssociatedObject(self, kDCTouchUpBlockKey);
	}


	- (void)dcOnTouchUp:(UIButton *)sender {
	    DCTouchUpBlock touchUp = self.dc_touchUpBlock;
	    if (touchUp) {
	        touchUp(sender);
	    }
	}
           @end

来看一下用法

    UIButton *button = [[UIButton alloc] initWithFrame:CGRectMake(20, 40, 280, 50)];
    button.backgroundColor = [UIColor blueColor];
    [button setTitle:@"点我啊" forState:UIControlStateNormal];
    [self.view addSubview:button];
    
    button.dc_touchUpBlock = ^(UIButton *sender){
        NSLog(@"%@",sender.titleLabel.text);
    };

运行结果是这样滴

DCCONTROL

是不是简单多了~

代码请查看 http://git.oschina.net/zcb1603999/DCTest

评论已关闭。