美文网首页
关联对象探索

关联对象探索

作者: Code_人生 | 来源:发表于2019-09-29 16:14 被阅读0次

一、关联属性

  • 属性声明
    • @property (nonatomic, copy) NSString *str;
    • setgetivar(变量)
  • 关联属性
    • objc_setAssociatedObject(id _Nonnull object, const void * _Nonnull key, id _Nullable value, objc_AssociationPolicy policy)
    • objc_getAssociatedObject(id _Nonnull object, const void * _Nonnull key)

二、源码分析-存

  • 1、objc4-750源码中搜索objc_setAssociatedObject
    • object 给那个对象设置、key 标识、value 设置的值、policy 缓存策略
// objc-runtime.mm
void objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy) {
    _object_set_associative_reference(object, (void *)key, value, policy);
}
  • 2、点击_object_set_associative_reference
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;
        //初始化 HashMap
        AssociationsHashMap &associations(manager.associations());
        //当前对象的地址按位取反(key)
        disguised_ptr_t disguised_object = DISGUISE(object);
        if (new_value) {
            // break any existing association.
            //<fisrt : disguised_object , second : ObjectAssociationMap>
            AssociationsHashMap::iterator i = associations.find(disguised_object);
            if (i != associations.end()) {
                // secondary table exists
                ObjectAssociationMap *refs = i->second;
                 //<fisrt : 标识(自定义的) , second : ObjcAssociation>
                ObjectAssociationMap::iterator j = refs->find(key);
                if (j != refs->end()) {
                    old_association = j->second;
                    //ObjcAssociation
                    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);
}
  • 2.1、点击acquireValue
static id acquireValue(id value, uintptr_t policy) {
    switch (policy & 0xFF) {
    case OBJC_ASSOCIATION_SETTER_RETAIN:
        return objc_retain(value);
    case OBJC_ASSOCIATION_SETTER_COPY:
        return ((id(*)(id, SEL))objc_msgSend)(value, SEL_copy);
    }
    return value;
}
  • 2.2、点击AssociationsManager
class AssociationsManager {
    // associative references: object pointer -> PtrPtrHashMap.
    static AssociationsHashMap *_map;
public:
    AssociationsManager()   { AssociationsManagerLock.lock(); }
    ~AssociationsManager()  { AssociationsManagerLock.unlock(); }
    
    AssociationsHashMap &associations() {
        if (_map == NULL)
            _map = new AssociationsHashMap();
        return *_map;
    }
};
  • 总结
    • 1、关联属性 ObjcAssociation 对象
    • 2、AssociationsManager管理AssociationsHashMap(存储的),对象的指针以及ObjectAssociationMap
    • 3、ObjectAssociationMap,存储关联对象数据结构
    • 4、关联属性和类,isa 指针的标识
    • 5、关联属性释放同当前对象的生命周期(isa)

三、源码分析-关联属性的移除

  • 1、点击setHasAssociatedObjects
  • 设置当前的isa指针,给一个标识,销毁的时候使用
inline void
objc_object::setHasAssociatedObjects()
{
    if (isTaggedPointer()) return;

 retry:
    isa_t oldisa = LoadExclusive(&isa.bits);
    isa_t newisa = oldisa;
    if (!newisa.nonpointer  ||  newisa.has_assoc) {
        ClearExclusive(&isa.bits);
        return;
    }
    newisa.has_assoc = true;
    if (!StoreExclusive(&isa.bits, oldisa.bits, newisa.bits)) goto retry;
}
  • 2、搜索dealloc
- (void)dealloc {
    _objc_rootDealloc(self);
}
  • 3、点击_objc_rootDealloc
void
_objc_rootDealloc(id obj)
{
    assert(obj);

    obj->rootDealloc();
}
  • 4、点击rootDealloc
inline void
objc_object::rootDealloc()
{
    if (isTaggedPointer()) return;  // fixme necessary?

    if (fastpath(isa.nonpointer  &&  
                 !isa.weakly_referenced  &&  
                 !isa.has_assoc  &&  
                 !isa.has_cxx_dtor  &&  
                 !isa.has_sidetable_rc))
    {
        assert(!sidetable_present());
        free(this);
    } 
    else {
        object_dispose((id)this);
    }
}
  • 5、点击object_dispose
id 
object_dispose(id obj)
{
    if (!obj) return nil;

    objc_destructInstance(obj);    
    free(obj);

    return nil;
}
  • 6、点击objc_destructInstance
void *objc_destructInstance(id obj) 
{
    if (obj) {
        // Read all of the flags at once for performance.
        bool cxx = obj->hasCxxDtor();
        bool assoc = obj->hasAssociatedObjects();

        // This order is important.
        if (cxx) object_cxxDestruct(obj);
        if (assoc) _object_remove_assocations(obj);
        obj->clearDeallocating();
    }

    return obj;
}
  • 7、点击_object_remove_assocations
void _object_remove_assocations(id object) {
    vector< ObjcAssociation,ObjcAllocator<ObjcAssociation> > elements;
    {
        AssociationsManager manager;
        AssociationsHashMap &associations(manager.associations());
        if (associations.size() == 0) return;
        disguised_ptr_t disguised_object = DISGUISE(object);
        AssociationsHashMap::iterator i = associations.find(disguised_object);
        if (i != associations.end()) {
            // copy all of the associations that need to be removed.
            ObjectAssociationMap *refs = i->second;
            for (ObjectAssociationMap::iterator j = refs->begin(), end = refs->end(); j != end; ++j) {
                elements.push_back(j->second);
            }
            // remove the secondary table.
            delete refs;
            associations.erase(i);
        }
    }
    // the calls to releaseValue() happen outside of the lock.
    for_each(elements.begin(), elements.end(), ReleaseValue());
}

四、关联属性手动释放

objc_removeAssociatedObjects(id _Nonnull object)

相关文章

  • 关联对象探索

    一、关联属性 属性声明@property (nonatomic, copy) NSString *str;set、...

  • OC底层面试

    关联对象补充 上节课我们在探索关联对象设置流程,在_object_set_associative_referenc...

  • 探索关联对象的原理

    思考:如何实现给分类“添加成员变量”? 默认情况下,因为分类底层结构的限制,不能添加成员变量到分类中。但可以通过关...

  • iOS底层-关联对象探索

    关联对象探索 其底层原理的实现,主要分为两部分: 通过objc_setAssociatedObject设值流程 通...

  • OC 底层探索 - Association 关联对象

    目录1. 关联对象1.1 使用场景1.2 使用方法 1.2.1 相关 API 1.2.2 objc_Associa...

  • OC_底层_isa探究

    isa与类关联的原理 OC对象的本质 先简单简介llbd相关知识: 在代码中探索对象本质: 在 main.cpp ...

  • Swift 为分类增加属性objc_getAssociated

    OC 获取关联对象 Swift 获取关联对象——错误的写法 Swift 获取关联对象——正确的写法 设置关联对象 ...

  • 探索AssociatedObject关联对象的内部实现

    AssociatedObject关联对象 为什么要引入关联对象? 一般我们需要对现有的类做扩展,可以通过继承、类别...

  • iOS runtime关联对象 objc_setAssociat

    关联对象的作用: 关联对象可以给某个对象关联一个或者多个其他对象,这些对象通过健来区分。 创建存储关联对象objc...

  • 关联对象

    关联对象的方式 关联对象源码基本思路 关联对象的结构:AssociationsHashManager // Ass...

网友评论

      本文标题:关联对象探索

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