OC关联对象小结(一)

作者: comst | 来源:发表于2016-03-21 02:09 被阅读1274次

    OC关联对象小结(一)

    使用场景

    为现有的类添加属性,变量

    在Objective-C中可以通过Category给一个现有的类添加属性(如NSObject),但是却不能添加实例变量,然而可以通过Associated Object间接地达到这一目的。示例代码展示了给NSObject添加实例变量。

    KVO创建一个关联的观察者

    相关函数

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

    objc_setAssociatedObject用于给对象添加关联对象,传nil可以移除相关的关联对象。
    objc_getAssocicatedObject用于获取关联对象的值。
    objc_removeAssociatedObject用于移除该对象的所有关联对象。如果打算只移除一部分则不能使用该方法。

    相关参数

    key:要保证全局唯一,key与关联的对象是一一对应关系。必须全局唯一。通常用@selector(methodName)作为key。
    value:要关联的对象。
    policy:关联策略。有五种关联策略。
    OBJC_ASSOCIATION_ASSIGN 等价于 @property(assign)
    OBJC_ASSOCIATION_RETAIN_NONATOMIC等价于 @property(strong, nonatomic)
    OBJC_ASSOCIATION_COPY_NONATOMIC等价于@property(copy, nonatomic)
    OBJC_ASSOCIATION_RETAIN等价于@property(strong,atomic)
    OBJC_ASSOCIATION_COPY等价于@property(copy, atomic)

    原理简介

    运行时通过map维系一张关联对象与被关联对象之间的关系。
    objc_setAssociatedObject的相关代码.

    void _object_set_associative_reference(id object, void *key, id value, uintptr_t policy) {
    // retain the new value (if any) outside the lock.
    ObjcAssociation old_association(0, nil);
    id new_value = value ? acquireValue(value, policy) : nil;
    {
    AssociationsManager manager;
    AssociationsHashMap &associations(manager.associations());
    disguised_ptr_t disguised_object = DISGUISE(object);
    if (new_value) {
    // break any existing association.
    AssociationsHashMap::iterator i = associations.find(disguised_object);
    if (i != associations.end()) {
    // secondary table exists
    ObjectAssociationMap *refs = i->second;
    ObjectAssociationMap::iterator j = refs->find(key);
    if (j != refs->end()) {
    old_association = j->second;
    j->second = ObjcAssociation(policy, new_value);
    } else {
    (*refs)[key] = ObjcAssociation(policy, new_value);
    }
    } else {
    // create the new association (first time).
    ObjectAssociationMap *refs = new ObjectAssociationMap;
    associations[disguised_object] = refs;
    (*refs)[key] = ObjcAssociation(policy, new_value);
    object->setHasAssociatedObjects();
    }
    } else {
    // setting the association to nil breaks the association.
    AssociationsHashMap::iterator i = associations.find(disguised_object);
    if (i !=  associations.end()) {
    ObjectAssociationMap *refs = i->second;
    ObjectAssociationMap::iterator j = refs->find(key);
    if (j != refs->end()) {
    old_association = j->second;
    refs->erase(j);
    }
    }
    }
    }
    // release the old value (outside of the lock).
    if (old_association.hasValue()) ReleaseValue()(old_association);
    }
    

    代码中涉及到的一些数据结构。

    1. AssociationsManager 是顶级的对象,维护了一个从 spinlock_t 锁到 AssociationsHashMap 哈希表的单例键值对映射;
    2. AssociationsHashMap 是一个无序的哈希表,维护了从对象地址到 ObjectAssociationMap 的映射;
    3. ObjectAssociationMap 是一个 C 中的 map ,维护了从 key 到 ObjcAssociation 的映射,即关联记录;
    4. ObjcAssociation 是一个 C 的类,表示一个具体的关联结构,主要包括两个实例变量,_policy 表示关联策略,_value 表示关联对象。
      流程图如下:



      看懂这个,那其他的几个也就懂了。

    相关文章

      网友评论

        本文标题:OC关联对象小结(一)

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