Objective-C关联引用

原创 2015年11月20日 11:54:23

在 Objective-C 中可以通过 Category 给一个现有的类添加属性,但是却不能添加实例变量,这似乎成为了 Objective-C 的一个明显短板。然而值得庆幸的是,我们可以通过 Associated Objects 来弥补这一不足。本文将结合 runtime 源码深入探究 Objective-C 中 Associated Objects 的实现原理。

读者需要着重关注以下三个问题:

  1. 关联对象被存储在什么地方,是不是存放在被关联对象本身的内存中?

  2. 关联对象的五种关联策略有什么区别,有什么坑?

  3. 关联对象的生命周期是怎样的,什么时候被释放,什么时候被移除?

使用场景

按照 Mattt Thompson 大神的文章 Associated Objects 中的说法,Associated Objects 主要有以下三个使用场景:

  1. 为现有的类添加私有变量以帮助实现细节;比如在分类中添加属性。

  2. 为现有的类添加公有属性;比如在分类中添加属性。

  3. 为 KVO 创建一个关联的观察者。

从本质上看,第 1 、2 个场景其实是一个意思,唯一的区别就在于新添加的这个属性是公有的还是私有的而已。就目前来说,我在实际工作中使用得最多的是第 2 个场景,而第 3 个场景我还没有使用过。

与 Associated Objects 相关的函数主要有三个,我们可以在 runtime 源码的 runtime.h 文件中找到它们的声明:

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);

这三个函数的命名对程序员非常友好,可以让我们一眼就看出函数的作用:

  1. objc_setAssociatedObject 用于给对象添加关联对象,传入 nil 则可以移除已有的关联对象;

  2. objc_getAssociatedObject 用于获取关联对象;

  3. objc_removeAssociatedObjects 用于移除一个对象的所有关联对象。

注:objc_removeAssociatedObjects 函数我们一般是用不上的,因为这个函数会移除一个对象的所有关联对象,将该对象恢复成“原始”状态。这样做就很有可能把别人添加的关联对象也一并移除,这并不是我们所希望的。所以一般的做法是通过给 objc_setAssociatedObject 函数传入 nil 来移除某个已有的关联对象。

key 值

关于前两个函数中的 key 值是我们需要重点关注的一个点,这个 key 值必须保证是一个对象级别(为什么是对象级别?看完下面的章节你就会明白了)的唯一常量。一般来说,有以下三种推荐的 key 值:

声明 static char kAssociatedObjectKey; ,使用 &kAssociatedObjectKey 作为 key 值;

声明 static void *kAssociatedObjectKey = &kAssociatedObjectKey; ,使用 kAssociatedObjectKey 作为 key 值

用 selector ,使用 getter 方法的名称作为 key 值。

本人更倾向于第二种.

关联策略

在给一个对象添加关联对象时有五种关联策略可供选择:


下面的1.2是对关联对象什么时候释放做了解释。

  1. 关联对象的释放时机与被移除的时机并不总是一致的,比如上面的 self.associatedObject_assign 所指向的对象在 ViewController 出现后就被释放了,但是 self.associatedObject_assign 仍然有值,还是保存的原对象的地址。如果之后再使用 self.associatedObject_assign 就会造成 Crash ,所以我们在使用弱引用的关联对象时要非常小心;

  2. 一个对象的所有关联对象是在这个对象被释放时调用的 _object_remove_assocations 函数中被移除的。

下面是一个针对alertView做的一个例子。

- (IBAction)didPressedAlert:(id)sender {

    UIAlertView * alert= [[UIAlertView alloc] initWithTitle:@"Question" message:@"哈哈" delegate:self cancelButtonTitle:@"cancel" otherButtonTitles:@"continue", nil];

    void(^block)(NSInteger) = ^(NSInteger buttonIndex){

        if (buttonIndex == 0) {

            NSLog(@"点击了取消");

        }else{

            NSLog(@"点击了确定");

        }

    };

    objc_setAssociatedObject(alert, (__bridge const void *)(ECOMyAlertViewKey), block, OBJC_ASSOCIATION_COPY);

    [alert show];

    

}


-(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex{

    void(^block)(NSInteger) = objc_getAssociatedObject(alertView, (__bridge const void *)(ECOMyAlertViewKey));

    block(buttonIndex);

}

Objective-C – 关联引用

你可以使用关联引用模拟在已存在的类上添加对象参数,这个功能只在Mac OS X v10.6和以上版本支持 在类外添加存储 使用关联引用,你可以对一个对象添加数据而不需要修改这个类定...
  • u010798355
  • u010798355
  • 2014年02月17日 21:09
  • 245

Objective-C关联引用

原创地址:http://www.guokr.com/blog/203413/ 比如说,如果你想向UIAlertView的delegate方法中传递一些信息,怎么办?继承UIAlertVi...
  • syansky1988
  • syansky1988
  • 2013年12月27日 13:29
  • 400

Objective-C Associative References(关联引用)

注:转自 http://gracelancy.com/?p=375 About 我之前写了一篇博文Objective-C Associative References(关联引用),介绍我在在研究obj...
  • songhongri
  • songhongri
  • 2013年09月19日 00:22
  • 3082

Objective-C 面向对象的基本概念——指针

oc语言中除了基本数据类型之外的变量类型都为指针类型,对象是通过指针对其进行操作的。 NSString *S;       //声明了一个NSString类型的指针变量,但它并没有指向任何一个对...
  • wuleihenbang
  • wuleihenbang
  • 2012年12月30日 14:38
  • 2135

浅析关联引用

关联引用可以给现有类添加属性,底层是如何实现的?快戳进来看看吧!以后开发爽了,因为添加属性使用关联引用来实现,添加方法使用类别实现!一切都是这么的简单!...
  • x1q2l3
  • x1q2l3
  • 2016年03月26日 20:43
  • 835

Objective-C如何使用对象集合学习系列之一

数组在列表中组织对象,列表通过整数进行索引。 字典通过键组织对象;字典中的每个对象都与某个键相关联,可以通过键检索对象。 集合包含对象,但不要假定这些对象以一定的顺序排列。集合中的对象也必须是唯一的(...
  • u011877416
  • u011877416
  • 2013年10月27日 09:11
  • 1983

Objective-C调用Swift

Objective-C调用Swift如果已经有了一个老的iOS应用,它是使用Objective-C编写的,而它的一些新功能需要采用Swift来编写,这时就可以从Objective-C调用Swift。O...
  • tonny_guan
  • tonny_guan
  • 2014年08月17日 17:04
  • 21269

Objective-C Associative References(关联引用) 续

About 我之前写了一篇博文Objective-C Associative References(关联引用),介绍我在在研究objc runtime的有趣的发现,但当时我并没有意识到这个技...
  • lw5180822
  • lw5180822
  • 2013年07月08日 17:36
  • 528

objective-c中关联引用的底层实现

我们知道关联引用(associative  references)可以为已存在的实例对象增加实例变量。该技术主要由以下三个函数实现相应的功能: 1.   void  objc_setAssociate...
  • wzxq123
  • wzxq123
  • 2016年05月25日 15:04
  • 1833

Objective-C 编程语言官网文档(七)-关联引用

声明:本文档仅为个人学习过程中顺手翻译之作,方便开发的同胞借鉴参考。如有觉得译的不好不到位的地方,欢迎指正,将及时做出更正 尽量尊重原文档,因为首次Objective-C,有些地方可能直译了没有...
  • Micheal_J
  • Micheal_J
  • 2012年06月05日 17:41
  • 7957
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Objective-C关联引用
举报原因:
原因补充:

(最多只允许输入30个字)