美文网首页
iOS日记6-关联对象

iOS日记6-关联对象

作者: Mcyboy007 | 来源:发表于2017-02-13 11:41 被阅读0次

1.使用场景

1.添加私有属性,用于更好地实现细节(声明在实现文件中)
2.添加公有属性,增强category的功能(声明在头文件中)
3.创建一个用于KVO的关联观察者

例:

#import "DKObject+Category.h"
#import <objc/runtime.h>

@implementation DKObject (Category)

- (NSString *)categoryProperty {
    return objc_getAssociatedObject(self, _cmd);
}

- (void)setCategoryProperty:(NSString *)categoryProperty {
    objc_setAssociatedObject(self, @selector(categoryProperty), categoryProperty, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
@end
分析:
  • runtime源码runtime.h中可以找到相关的函数定义:
//1.添加关联对象,传入nil时,相当于清空该关联对象的值
void objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy);
//2.获取关联对象
id objc_getAssociatedObject(id object, const void *key);
//3.移除所有关联对象,一般不使用,这样会把所有的关联对象都移除。
void objc_removeAssociatedObjects(id object);
  • key值的获取:key值必须是一个对象级别的唯一常量。通常有三种写法:
    1)声明static char kAssociatedObejctKey;使用&kAssociatedObejctKey作为Key
    2)声明static void *kAssociatedObejctKey = &kAssociatedObejctKey;使用kAssociatedObejctKey 作为Key
    3)使用selector,用getter方法作为Key。例如@selector(函数名称),更简单就是使用_cmd(代表当前方法的选择子)。这样可以去为Key命名的烦恼,推荐!

  • 关联策略:
    OBJC_ASSOCIATION_ASSIGN
    OBJC_ASSOCIATION_RETAIN_NONATOMIC
    OBJC_ASSOCIATION_COPY_NONATOMIC
    OBJC_ASSOCIATION_RETAIN
    OBJC_ASSOCIATION_COPY

2.实现原理

//runtime中的源代码,省略了具体实现:
void _object_set_associative_reference(id object, void *key, id value, uintptr_t policy) {
    ObjcAssociation old_association(0, nil);
    id new_value = value ? acquireValue(value, policy) : nil;
    {
        AssociationsManager manager;
        AssociationsHashMap &associations(manager.associations());
        ObjectAssociationMap *refs = i->second;
        ...
    }
    if (old_association.hasValue()) ReleaseValue()(old_association);
}
分析:
  • AssociationsManager
class AssociationsManager {
    static spinlock_t _lock;
    static AssociationsHashMap *_map;
public:
    AssociationsManager()   { _lock.lock(); }
    ~AssociationsManager()  { _lock.unlock(); }

    AssociationsHashMap &associations() {
        if (_map == NULL)
            _map = new AssociationsHashMap();
        return *_map;
    }
};

spinlock_t AssociationsManager::_lock;
AssociationsHashMap *AssociationsManager::_map = NULL;

它维护了 spinlock_t 和 AssociationsHashMap 的单例,初始化它的时候会调用 lock.lock() 方法,在析构时会调用 lock.unlock(),而 associations 方法用于取得一个全局的 AssociationsHashMap 单例.也就是说 AssociationsManager 通过持有一个自旋锁 spinlock_t 保证对 AssociationsHashMap 的操作是线程安全的,即每次只会有一个线程对 AssociationsHashMap 进行操作

  • AssociationsHashMap
  • ObjcAssociationMap

ObjectAssociationMap 则保存了从 key 到关联对象 ObjcAssociation 的映射,这个数据结构保存了当前对象对应的所有关联对象

  • ObjcAssociation
    ObjcAssociation 就是真正的关联对象的类,上面的所有数据结构只是为了更好的存储它。
class ObjcAssociation {
    uintptr_t _policy;
    id _value;
public:
    ObjcAssociation(uintptr_t policy, id value) : _policy(policy), _value(value) {}
    ObjcAssociation() : _policy(0), _value(nil) {}

    uintptr_t policy() const { return _policy; }
    id value() const { return _value; }

    bool hasValue() { return _value != nil; }
};

结论:

问题:在分类中到底能否实现属性?
  • 如果你把属性理解为通过方法访问的实例变量,我相信这个问题的答案是不能,因为分类不能为类增加额外的实例变量。
  • 不过如果属性只是一个存取方法以及存储值的容器的集合,那么分类是可以实现属性的。

分类中对属性的实现其实只是实现了一个看起来像属性的接口而已。

问题:关联对象又是如何实现并且管理的呢?
  • 关联对象其实就是 ObjcAssociation 对象
  • 关联对象由 AssociationsManager 管理并在 AssociationsHashMap 存储
  • 对象的指针以及其对应 ObjectAssociationMap 以键值对的形式存储在 AssociationsHashMap 中
  • ObjectAssociationMap 则是用于存储关联对象的数据结构
  • 每一个对象都有一个标记位 has_assoc 指示对象是否含有关联对象

参考资料

1.http://nshipster.cn/associated-objects/
2.http://blog.leichunfeng.com/blog/2015/06/26/objective-c-associated-objects-implementation-principle/
3.https://github.com/Draveness/iOS-Source-Code-Analyze/blob/master/contents/objc/%E5%85%B3%E8%81%94%E5%AF%B9%E8%B1%A1%20AssociatedObject%20%E5%AE%8C%E5%85%A8%E8%A7%A3%E6%9E%90.md

相关文章

  • iOS日记6-关联对象

    1.使用场景 1.添加私有属性,用于更好地实现细节(声明在实现文件中)2.添加公有属性,增强category的功能...

  • iOS关联对象技术原理

    iOS关联对象技术原理 iOS关联对象技术原理

  • 6-关联对象

    属性 在类中声明一个属性会生成成员变量并声明和实现对应的set,get方法 在分类中声明一个属性只会声明对应的se...

  • iOS底层原理总结 - 关联对象实现原理

    iOS底层原理总结 - 关联对象实现原理 iOS底层原理总结 - 关联对象实现原理

  • iOS Objective-C 关联对象

    iOS Objective-C 关联对象 1. 关联对象简介 对于关联对象,我们熟悉它的地方就是给分类添加属性。虽...

  • iOS对象关联

    什么是关联对象 关联对象是指某个OC对象通过一个唯一的key连接到一个类的实例上。 举个例子:xiaoming是P...

  • iOS:关联对象

    目录一,添加属性二,基本知识三,底层原理四,注意点 一,添加属性 1,在类中添加属性,系统会自动生成带下划线的成员...

  • iOS 关联对象

    在平时的工作中经常碰到给类别添加属性的操作,那么实现思路是怎么样的呢? 代码实现:新建一个Person类和Pers...

  • iOS 关联对象

    可以不改变源码的情况下增加实例变量。可与分类配合使用,为分类增加属性。(类别是不能添加成员变量的(property...

  • iOS 关联对象

    关联对象简单的说就是运用oc语言的运行时特性(runtime),给类别加属性(当然不止加属性).正常的类中创建一个...

网友评论

      本文标题:iOS日记6-关联对象

      本文链接:https://www.haomeiwen.com/subject/lsywittx.html