zoukankan      html  css  js  c++  java
  • category和关联对象

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

    MyClass+Category1.h:

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

    MyClass+Category1.m:

    #import "MyClass+Category1.h"
    #import <objc/runtime.h>
    
    @implementation MyClass (Category1)
    
    + (void)load
    {
        NSLog(@"%@",@"load in Category1");
    }
    
    - (void)setName:(NSString *)name
    {
        objc_setAssociatedObject(self,
                                 "name",
                                 name,
                                 OBJC_ASSOCIATION_COPY);
    }
    
    - (NSString*)name
    {
        NSString *nameObject = objc_getAssociatedObject(self, "name");
        return nameObject;
    }
    
    @end
    

    但是关联对象又是存在什么地方呢? 如何存储? 对象销毁时候如何处理关联对象呢?
    我们去翻一下runtime的源码,在objc-references.mm文件中有个方法_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;
            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);
                    _class_setInstancesHaveAssociatedObjects(_object_getClass(object));
                }
            } 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);
    }
    

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

    class AssociationsManager {
        static OSSpinLock _lock;
        static AssociationsHashMap *_map;               // associative references:  object pointer -> PtrPtrHashMap.
    public:
        AssociationsManager()   { OSSpinLockLock(&_lock); }
        ~AssociationsManager()  { OSSpinLockUnlock(&_lock); }
    
        AssociationsHashMap &associations() {
            if (_map == NULL)
                _map = new AssociationsHashMap();
            return *_map;
        }
    };
    

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

    void *objc_destructInstance(id obj) 
    {
        if (obj) {
            Class isa_gen = _object_getClass(obj);
            class_t *isa = newcls(isa_gen);
    
            // Read all of the flags at once for performance.
            bool cxx = hasCxxStructors(isa);
            bool assoc = !UseGC && _class_instancesHaveAssociatedObjects(isa_gen);
    
            // This order is important.
            if (cxx) object_cxxDestruct(obj);
            if (assoc) _object_remove_assocations(obj);
    
            if (!UseGC) objc_clear_deallocating(obj);
        }
    
        return obj;
    }
    

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

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

  • 相关阅读:
    网络对抗技术 20181216 Exp6 MSF基础应用
    实验一-密码引擎-加密API研究
    网络对抗技术 20181216 Exp5 信息搜集与漏洞扫描
    网络对抗技术 20181216 Exp4 恶意代码分析原理与实践说明
    网络对抗技术 20181216 Exp3 免杀原理与实践
    用Visual Studio 2019 创建C#窗体项目
    EL表达式的学习
    session学习
    mysql+javaWeb+jdbc+tomcat开发中的中文乱码处理
    java集合
  • 原文地址:https://www.cnblogs.com/feng9exe/p/8400926.html
Copyright © 2011-2022 走看看