如上所见,我们知道在category里面是无法为category添加实例变量的。但是我们很多时候需要在category中添加和对象关联的值,这个时候可以求助关联对象来实现。

MyClass+Category1.h:

  1. #import "MyClass.h"
  2. @interface MyClass (Category1)
  3. @property(nonatomic,copy) NSString *name;
  4. @end

MyClass+Category1.m:

  1. #import "MyClass+Category1.h"
  2. #import <objc/runtime.h>
  3. @implementation MyClass (Category1)
  4. + (void)load
  5. {
  6. NSLog(@"%@",@"load in Category1");
  7. }
  8. - (void)setName:(NSString *)name
  9. {
  10. objc_setAssociatedObject(self,
  11. "name",
  12. name,
  13. OBJC_ASSOCIATION_COPY);
  14. }
  15. - (NSString*)name
  16. {
  17. NSString *nameObject = objc_getAssociatedObject(self, "name");
  18. return nameObject;
  19. }
  20. @end

但是关联对象又是存在什么地方呢? 如何存储? 对象销毁时候如何处理关联对象呢?
我们去翻一下runtime的源码,在objc-references.mm文件中有个方法_object_set_associative_reference:

  1. void _object_set_associative_reference(id object, void *key, id value, uintptr_t policy) {
  2. // retain the new value (if any) outside the lock.
  3. ObjcAssociation old_association(0, nil);
  4. id new_value = value ? acquireValue(value, policy) : nil;
  5. {
  6. AssociationsManager manager;
  7. AssociationsHashMap &associations(manager.associations());
  8. disguised_ptr_t disguised_object = DISGUISE(object);
  9. if (new_value) {
  10. // break any existing association.
  11. AssociationsHashMap::iterator i = associations.find(disguised_object);
  12. if (i != associations.end()) {
  13. // secondary table exists
  14. ObjectAssociationMap *refs = i->second;
  15. ObjectAssociationMap::iterator j = refs->find(key);
  16. if (j != refs->end()) {
  17. old_association = j->second;
  18. j->second = ObjcAssociation(policy, new_value);
  19. } else {
  20. (*refs)[key] = ObjcAssociation(policy, new_value);
  21. }
  22. } else {
  23. // create the new association (first time).
  24. ObjectAssociationMap *refs = new ObjectAssociationMap;
  25. associations[disguised_object] = refs;
  26. (*refs)[key] = ObjcAssociation(policy, new_value);
  27. _class_setInstancesHaveAssociatedObjects(_object_getClass(object));
  28. }
  29. } else {
  30. // setting the association to nil breaks the association.
  31. AssociationsHashMap::iterator i = associations.find(disguised_object);
  32. if (i != associations.end()) {
  33. ObjectAssociationMap *refs = i->second;
  34. ObjectAssociationMap::iterator j = refs->find(key);
  35. if (j != refs->end()) {
  36. old_association = j->second;
  37. refs->erase(j);
  38. }
  39. }
  40. }
  41. }
  42. // release the old value (outside of the lock).
  43. if (old_association.hasValue()) ReleaseValue()(old_association);
  44. }

我们可以看到所有的关联对象都由AssociationsManager管理,而AssociationsManager定义如下:

  1. class AssociationsManager {
  2. static OSSpinLock _lock;
  3. static AssociationsHashMap *_map; // associative references: object pointer -> PtrPtrHashMap.
  4. public:
  5. AssociationsManager() { OSSpinLockLock(&_lock); }
  6. ~AssociationsManager() { OSSpinLockUnlock(&_lock); }
  7. AssociationsHashMap &associations() {
  8. if (_map == NULL)
  9. _map = new AssociationsHashMap();
  10. return *_map;
  11. }
  12. };

AssociationsManager里面是由一个静态AssociationsHashMap来存储所有的关联对象的。这相当于把所有对象的关联对象都存在一个全局map里面。而map的的key是这个对象的指针地址(任意两个不同对象的指针地址一定是不同的),而这个map的value又是另外一个AssociationsHashMap,里面保存了关联对象的kv对。
而在对象的销毁逻辑里面,见objc-runtime-new.mm:

  1. void *objc_destructInstance(id obj)
  2. {
  3. if (obj) {
  4. Class isa_gen = _object_getClass(obj);
  5. class_t *isa = newcls(isa_gen);
  6. // Read all of the flags at once for performance.
  7. bool cxx = hasCxxStructors(isa);
  8. bool assoc = !UseGC && _class_instancesHaveAssociatedObjects(isa_gen);
  9. // This order is important.
  10. if (cxx) object_cxxDestruct(obj);
  11. if (assoc) _object_remove_assocations(obj);
  12. if (!UseGC) objc_clear_deallocating(obj);
  13. }
  14. return obj;
  15. }

嗯,runtime的销毁对象函数objc_destructInstance里面会判断这个对象有没有关联对象,如果有,会调用_object_remove_assocations做关联对象的清理工作。

http://www.cnblogs.com/feng9exe/p/7133763.html

category和关联对象的更多相关文章

  1. iOS Category 添加属性实现原理 - 关联对象

    iOS Category 添加属性实现原理 - 关联对象 RunTime为Category动态关联对象 使用RunTime给系统的类添加属性,首先需要了解对象与属性的关系.对象一开始初始化的时候其属性 ...

  2. 使用关联对象(AssociatedObject)为UIButton添加Block响应

    在开发中,要给UIButton添加点击事件的话,通常的做法是这样的 UIButton *button = [UIButton buttonWithType:UIButtonTypeSystem]; [ ...

  3. iOS开发--Runtime的简单使用之关联对象

    一.Runtime关联对象的方法简介: 在<objc/runtime.h>中,有三个关联的方法,分别是: objc_setAssociatedObject objc_getAssociat ...

  4. Runtime之成员变量&属性&关联对象

    上篇介绍了Runtime类和对象的相关知识点,在4.5和4.6小节,也介绍了成员变量和属性的一些方法应用.本篇将讨论实现细节的相关内容. 在讨论之前,我们先来介绍一个很冷僻但又很有用的一个关键字:@e ...

  5. AssociatedObject关联对象原理实现

    介绍 关联对象(AssociatedObject)是Objective-C 2.0运行时的一个特性,允许开发者对已经存在的类在扩展中添加自定义的属性.在实际生产过程中,比较常用的方式是给分类(Cate ...

  6. Runtime - Associated Objects (关联对象) 的实现原理

    主要围绕3个方面说明runtime-Associated Objects (关联对象) 1. 使用场景 2.如何使用 3.底层实现 3.1  实现原理 3.2 关联对象被存储在什么地方,是不是存放在被 ...

  7. Objective-C——关联对象

    动态语言 OC是一种动态语言,它的方法,对象的类型都是到运行的时候才能够确定的.所以这就使得OC存在了关联对象这一强大的机制. 关联对象 所谓关联对象,其实就是我们在运行时对一个已存在的对象上面绑定一 ...

  8. 关联对象 AssociatedObject 完全解析

    我们在 iOS 开发中经常需要使用分类(Category),为已经存在的类添加属性的需求,但是使用 @property 并不能在分类中正确创建实例变量和存取方法. 不过,通过 Objective-C ...

  9. Effective Objective-C 2.0 — 第10条:在既有类中使用关联对象存放自定义数据

    可以通过“关联对象”机制来把两个对象连起来 定义关联对象时可指定内存管理语义,用以模仿定义属性时所采用的“拥有关系”与“非拥有关系” 只有在其他做法不可行时才应选用关联对象,因为这种做法通常会引入难于 ...

随机推荐

  1. 开发辅助 | 前端开发工程师对 UI设计、交互设计的认知

    1.UI 用户界面 UI:User Interfase 用户界面 UID:User Interfase Designer 用户界面设计师,多指移动 app 的界面设计: 2.一个合格的 UI 设计师, ...

  2. Dragon Balls[HDU3635]

    Dragon Balls Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total S ...

  3. luogu P2000 拯救世界 生成函数_麦克劳林展开_python

    模板题. 将所有的多项式按等比数列求和公式将生成函数压缩,相乘后麦克劳林展开即可. Code: n=int(input()) print((n+1)*(n+2)*(n+3)*(n+4)//24)

  4. Pyhton学习——Day9(阶段性练习)

    # 1.文件内容如下,标题为:姓名,性别,年纪,薪资## egon male 18 3000# alex male 38 30000# wupeiqi female 28 20000# yuanhao ...

  5. 【BZOJ3309】DZY Loves Math - 莫比乌斯反演

    题意: 对于正整数n,定义$f(n)$为$n$所含质因子的最大幂指数.例如$f(1960)=f(2^3 * 5^1 * 7^2)=3$,$f(10007)=1$,$f(1)=0$. 给定正整数$a,b ...

  6. input只能输入数字或两位小数

    /** * [只能输入数字和两位小数] * 举例:<input type="text" onkeyup="num(this)" size="10 ...

  7. 用 JavaScript 实现简单拼图游戏

    本篇主要讲解,如何利用原生的 JavaScript 来实现一个简单的拼图小游戏. 线上体验地址:拼图 一.游戏的基础逻辑 想用一门语言来开发游戏,必须先了解如何使用这门语言来实现一些基础逻辑,比如图像 ...

  8. tomcat闪退无法启动 the catalina_home environment variable is not defined correctly this environment variable is needed to run this program

    未成功配置CATALINA_HOME 1.计算机>属性>环境变量, 新建环境变量.变量名为CATALINA_HOME ,变量值tomcat的解压目录,注意后面不用多加“\”或者“;” 2. ...

  9. 紫书 例题8-3 UVa 1152(中途相遇法)

    这道题要逆向思维, 就是求出答案的一部分, 然后反过去去寻找答案存不存在. 其实很多其他题都用了这道题目的方法, 自己以前都没有发现, 这道题专门考这个方法.这个方法可以没有一直往下求, 可以省去很多 ...

  10. Python3的URL编码解码

    前言 博主最近在用python3练习一些爬虫脚本的时候,发现一些url的编码问题,在浏览器提交请求api时,如果url中包含汉子,就会被自动编码掉.呈现的结果是 ==> %xx%xx%xx.如果 ...