【引】关联对象(Associated Object)学习笔记

2016-09-02  本文已影响36人  Jin丶hy

由于 分类(Category) 并不能实现对类的成员变量动态添加,这个时候,Objective-C就提供了一个解决方案:关联对象(Associated Object)

关联对象类似于成员变量,不过是在运行时添加的。

我们可以把关联对象想象成一个Objective-C对象(如字典),这个对象通过给定的key连接到类的一个实例上。不过由于使用的是C接口,所以key是一个void指针(const void *)。我们还需要指定一个内存管理策略,以告诉Runtime如何管理这个对象的内存。这个内存管理的策略可以由以下值指定:

OBJC_ASSOCIATION_ASSIGN 
OBJC_ASSOCIATION_RETAIN_NONATOMIC 
OBJC_ASSOCIATION_COPY_NONATOMIC 
OBJC_ASSOCIATION_RETAIN 
OBJC_ASSOCIATION_COPY 

当宿主对象被释放时,会根据指定的内存管理策略来处理关联对象。如果指定的策略是assign,则宿主释放时,关联对象不会被释放;而如果指定的是retain或者是copy,则宿主释放时,关联对象会被释放。我们甚至可以选择是否是自动retain/copy。当我们需要在多个线程中处理访问关联对象的多线程代码时,这就非常有用了。

我们将一个对象连接到其它对象所需要做的就是下面两行代码:

static char myKey; 
 
objc_setAssociatedObject(self, &myKey, anObject, OBJC_ASSOCIATION_RETAIN); 

在这种情况下,self对象将获取一个新的关联的对象anObject,且内存管理策略是自动retain关联对象,当self对象释放时,会自动release关联对象。另外,如果我们使用同一个key来关联另外一个对象时,也会自动释放之前关联的对象,这种情况下,先前的关联对象会被妥善地处理掉,并且新的对象会使用它的内存。

eg.

假定我们想要动态地将一个Tap手势操作连接到任何UIView中,并且根据需要指定点击后的实际操作。这时候我们就可以将一个手势对象及操作的block对象关联到我们的UIView对象中。这项任务分两部分。首先,如果需要,我们要创建一个手势识别对象并将它及block做为关联对象。如下代码所示:

- (void)setTapActionWithBlock:(void (^)(void))block 
{ 
    UITapGestureRecognizer *gesture = objc_getAssociatedObject(self, &kDTActionHandlerTapGestureKey); 
 
    if (!gesture) 
    { 
        gesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(__handleActionForTapGesture:)]; 
        [self addGestureRecognizer:gesture]; 
        objc_setAssociatedObject(self, &kDTActionHandlerTapGestureKey, gesture, OBJC_ASSOCIATION_RETAIN); 
    } 
 
    objc_setAssociatedObject(self, &kDTActionHandlerTapBlockKey, block, OBJC_ASSOCIATION_COPY); 
} 

这段代码检测了手势识别的关联对象。如果没有,则创建并建立关联关系。同时,将传入的块对象连接到指定的key上。注意block对象的关联内存管理策略。

- (void)__handleActionForTapGesture:(UITapGestureRecognizer *)gesture 
{ 
    if (gesture.state == UIGestureRecognizerStateRecognized) 
    { 
        void(^action)(void) = objc_getAssociatedObject(self, &kDTActionHandlerTapBlockKey); 
 
        if (action) 
        { 
            action(); 
        } 
    } 
} 

我们需要检测手势识别对象的状态,因为我们只需要在点击手势被识别出来时才执行操作。

从上面的例子我们可以看到,关联对象使用起来并不复杂。它让我们可以动态地增强类现有的功能。我们可以在实际编码中灵活地运用这一特性。

具体请看大神:
Objective-C Runtime 运行时之二:成员变量与属性

上一篇下一篇

猜你喜欢

热点阅读