美文网首页
十六、关联对象

十六、关联对象

作者: KB_MORE | 来源:发表于2020-10-26 15:05 被阅读0次

分类和类别

1: category: 类别,分类

  • 专门用来给类添加新的方法
  • 不能给类添加成员 属性,添加了成员变量,也无法取到
  • 注意:其实可以通过runtime给分类添加属性
  • 分类中用@property 定义变量,只会生成变量的getter, setter方法的声明,不能生成方法实现和带下划线的成员变量。

最后一条怎么证明呢?
我们在分类中添加属性,


图片.png

在外部使用时, 编译时不会报错的


图片.png
运行时报错
图片.png

2: extension:类扩展

  • 可以说成是特殊的分类,也称作匿名分类
  • 可以给类添加成员属性,但是是私有变量
  • 可以给类添加方法,也是私有方法

关联对象底层

1.objc_setAssociatedObject
- (void)setCate_name:(NSString *)cate_name{

    objc_setAssociatedObject(self, "cate_name", cate_name, OBJC_ASSOCIATION_COPY_NONATOMIC);
}
2.SetAssocHook.get()
void
objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy)
{
    SetAssocHook.get()(object, key, value, policy);
}
3._base_objc_setAssociatedObject
static ChainedHookFunction<objc_hook_setAssociatedObject> SetAssocHook{_base_objc_setAssociatedObject};
4._object_set_associative_reference
static void
_base_objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy)
{
  _object_set_associative_reference(object, key, value, policy);
}

5._object_set_associative_reference

void
_object_set_associative_reference(id object, const void *key, id value, uintptr_t policy)
{
    // This code used to work when nil was passed for object and key. Some code
    // probably relies on that to not crash. Check and handle it explicitly.
    // rdar://problem/44094390
    if (!object && !value) return;

    if (object->getIsa()->forbidsAssociatedObjects())
        _objc_fatal("objc_setAssociatedObject called on instance (%p) of class %s which does not allow associated objects", object, object_getClassName(object));

    DisguisedPtr<objc_object> disguised{(objc_object *)object};
    ObjcAssociation association{policy, value};

    // retain the new value (if any) outside the lock.
    association.acquireValue();

    {
        AssociationsManager manager;
        
        AssociationsHashMap &associations(manager.get());

        if (value) {
            auto refs_result = associations.try_emplace(disguised, ObjectAssociationMap{});
            if (refs_result.second) {
                /* it's the first association we make */
                object->setHasAssociatedObjects();
            }

            /* establish or replace the association */
            auto &refs = refs_result.first->second;
            auto result = refs.try_emplace(key, std::move(association));
            if (!result.second) {
                association.swap(result.first->second);
            }
        } else {
            auto refs_it = associations.find(disguised);
            if (refs_it != associations.end()) {
                auto &refs = refs_it->second;
                auto it = refs.find(key);
                if (it != refs.end()) {
                    association.swap(it->second);
                    refs.erase(it);
                    if (refs.size() == 0) {
                        associations.erase(refs_it);

                    }
                }
            }
        }

    }

    // release the old value (outside of the lock).
    association.releaseHeldValue();
}

结构如下图


图片.png
图片.png

AssociationHashMap 是全局的, 唯一的

关联对象需不需要在的dealloc手动移除?

当我们对象释放时,会调用dealloc

1、C++函数释放 :objc_cxxDestruct
2、移除关联属性:_object_remove_assocations
3、将弱引用自动设置nil:weak_clear_no_lock(&table.weak_table, (id)this);
4、引用计数处理:table.refcnts.erase(this)
5、销毁对象:free(obj)

所以,关联对象不需要我们手动移除,会在对象析构即dealloc时释放

dealloc 源码

dealloc的源码查找路径为:dealloc -> _objc_rootDealloc -> rootDealloc -> object_dispose(释放对象)-> objc_destructInstance -> _object_remove_assocations

1. dealloc
- (void)dealloc {
    _objc_rootDealloc(self);
}

2._objc_rootDealloc
void
_objc_rootDealloc(id obj)
{
    ASSERT(obj);

    obj->rootDealloc();
}


3.rootDealloc isa.has_assoc 发现其中有关联属性时设置bool值,当有这些条件时,需要进入else流程
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);
    }
}

4.object_dispose 销毁实例对象
id 
object_dispose(id obj)
{
    if (!obj) return nil;

    objc_destructInstance(obj);    
    free(obj);

    return nil;
}
5.objc_destructInstance 在这里有移除关联属性的方法_object_remove_assocations
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;
}
6._object_remove_assocations 关联属性的移除,主要是从全局哈希map中找到相关对象的迭代器,然后将迭代器中关联属性,从头到尾的移除
void
_object_remove_assocations(id object)
{
    ObjectAssociationMap refs{};

    {
        AssociationsManager manager;
        AssociationsHashMap &associations(manager.get());
        AssociationsHashMap::iterator i = associations.find((objc_object *)object);
        if (i != associations.end()) {
            refs.swap(i->second);
            associations.erase(i);
        }
    }

    // release everything (outside of the lock).
    for (auto &i: refs) {
        i.second.releaseHeldValue();
    }
}

相关文章

  • 十六、关联对象

    分类和类别 1: category: 类别,分类 专门用来给类添加新的方法 不能给类添加成员 属性,添加了成员变量...

  • Swift 为分类增加属性objc_getAssociated

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

  • iOS runtime关联对象 objc_setAssociat

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

  • 关联对象

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

  • 关联对象

    关联对象原理 关联对象并不是存储在被关联对象本身内存中,关联对象存储在全局的统一的一个AssociationsMa...

  • iOS 关联对象

    概述 关联对象顾名思义,就是给对象关联对象的意思,一个对象可以关联多个其他对象,这些对象通过key来区分,存储对象...

  • 关联对象

    关联对象会用被关联对象作为key,将关联对象存储到全局的哈希表里。 AssociationHashMap Asso...

  • iOS关联对象技术原理

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

  • 关联对象

    分类里面添加成员变量, 分类里面是不能直接添加成员变量的,但是可以通过runtime间接添加成员变量。 为什么...

  • 关联对象

    能否为分类添加 “成员变量” ? 为分类所添加的成员变量添加在哪里? 所有对象的关联内容都在同一个全局容器内关联对...

网友评论

      本文标题:十六、关联对象

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