OC学习之Runtime之关联对象

坚持 成长 每日一篇

前言

在Runtime中有一个我们经常忽略的特性就是关联对象特性。
关联对象类似于成员变量,不同的是关联对象是在类创建实例后添加进去的。所以不能通过Runtime的获取成员变量的方法获取相关信息。
注意:对关联函数的操作只能通过下面的C函数进行操作。

// 设置关联对象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 ); 

在对于系统的类如果我们想个类添加属性,由于我们不能给类别里面添加成员变量,只能通过创建该类的子类来实现。
Objective-C针对这一问题,提供了一个解决方案:即关联对象(Associated Object)。
我们可以把关联对象想象成一个Objective-C对象(如字典),这个对象通过给定的key连接到类的一个实例上。不过由于使用的是C接口,所以key是一个void指针(const void *)。我们还需要指定一个内存管理策略,以告诉Runtime如何管理这个对象的内存。这个内存管理的策略可以由以下值指定:

enum {
    OBJC_ASSOCIATION_ASSIGN = 0, //弱引用,对象销毁不会造成关联对象的引用计数变化
    OBJC_ASSOCIATION_RETAIN_NONATOMIC = 1, //强引用,不支持多线程安全
    OBJC_ASSOCIATION_COPY_NONATOMIC = 3, //深拷贝,不支持多线程安全
    OBJC_ASSOCIATION_RETAIN = 01401, //强引用支持线程安全
    OBJC_ASSOCIATION_COPY = 01403  //深拷贝,支持线程安全
};

例子

创建一个UIView的分类,我们要给分类添加一个单击手势回调代码块。
UIView+Tap.h

#import <UIKit/UIKit.h>

@interface UIView (Tap)
- (void)setTapActionWithBlock:(void (^)(void))block;
@end

UIView+Tap.m

#import "UIView+Tap.h"
#import <objc/runtime.h>
#define keyForAction "action"
#define keyForRecognizer "Recognizer"
@implementation UIView (Tap)
- (void)setTapActionWithBlock:(void (^)(void))block
{
    //如果这里不使用关联对象,你可能需要不停移除手势,然后再创建手势
    UITapGestureRecognizer *gesture = objc_getAssociatedObject(self,keyForRecognizer);
    if (!gesture)
    {
        gesture = [[UITapGestureRecognizer alloc] initWithTarget:self      action:@selector(actionForTapGesture:)];
        [self addGestureRecognizer:gesture];
        objc_setAssociatedObject(self, keyForRecognizer, gesture,  OBJC_ASSOCIATION_RETAIN);
    }
    //这里可以成功的添加一个关联对象给后面的手势回调函数使用,而不需要通过全局变量或成员变量。
    objc_setAssociatedObject(self, keyForAction, block, OBJC_ASSOCIATION_COPY);
}
//实现回调函数
- (void)actionForTapGesture:(UITapGestureRecognizer *)gesture
{
    if (gesture.state == UIGestureRecognizerStateRecognized)
    {
        //我们只能通过objc_getAssociatedObject来取出关联对象
        void(^action)(void) = objc_getAssociatedObject(self, keyForAction);
        if (action)
        { 
            action(); 
        } 
    }
}
@end

在控制器里面测试

- (void)viewDidLoad {
    [super viewDidLoad];
    //这样实现了不需要创建分类,很好的拓展了已有的UIView类。
    [self.view setTapActionWithBlock:^{
        NSLog(@"is tap");
    }];
}

运行程序我们就会看到当我们点击控制视图时候输出

2015-09-15 09:59:21.869 test[5410:381831] is tap
2015-09-15 09:59:23.005 test[5410:381831] is tap
2015-09-15 09:59:23.545 test[5410:381831] is tap

总结:关联对象是一个非常实用的Runtime特性。可以很好的帮我们解决开发中遇到很多如传值,扩展对象等问题。

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值