美文网首页
分类的关联属性

分类的关联属性

作者: Bel李玉 | 来源:发表于2020-01-02 23:32 被阅读0次
类扩展和分类的区别
  • category:就是类别,也叫分类,专门用来给类添加新的方法,不能给类添加成员属性,但可以使用runtime关联对象,使用property定义变量,只会生成变量的gettter,setter方法的声明,不能生成方法实现和带下划线的成员变量。

  • 类扩展:可以给类添加成员属性,但是是私有变量。可以给类添加方法,也只是私有方法。

关联对象分析

在iOS分类中,我们可以使用在分类中添加关联属性,主要是通过void objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy)id objc_getAssociatedObject(id object, const void *key)这两个函数进行设置,通过objc源码观察一下具体实现过程

objc_setAssociatedObject

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

首先会根据内存管理策略,来进行内存管理,分别进行retain和copy操作。

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

然后,创建 ObjcAssociation对象,存储在 AssociationsHashMap中

objc_getAssociatedObject

id _object_get_associative_reference(id object, void *key) {
    id value = nil;
    uintptr_t policy = OBJC_ASSOCIATION_ASSIGN;
    {
        AssociationsManager manager;
        AssociationsHashMap &associations(manager.associations());
        disguised_ptr_t disguised_object = DISGUISE(object);
        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()) {
                ObjcAssociation &entry = j->second;
                value = entry.value();
                policy = entry.policy();
                if (policy & OBJC_ASSOCIATION_GETTER_RETAIN) {
                    objc_retain(value);
                }
            }
        }
    }
    if (value && (policy & OBJC_ASSOCIATION_GETTER_AUTORELEASE)) {
        objc_autorelease(value);
    }
    return value;
}

在读取的过程中,根据对象地址按位取反读取AssociationsHashMap对象,然后找到对应的ObjectAssociationMap对象,然后取出value值

关联属性的释放

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

如果对象有关联属性,在对象dealloc时,会调用 object_dispose((id)this),然后调用 objc_destructInstance(obj),如果该对象有关联属性,会调用 _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());
}

从而完成了关联属性的释放。

相关文章

  • UIAlertView关联属性 + 分类

    UIAlertView关联属性 UIAlertView 分类 增加block属性

  • 分类的关联属性

    类扩展和分类的区别 category:就是类别,也叫分类,专门用来给类添加新的方法,不能给类添加成员属性,但可以使...

  • Runtime 关联对象, 可在分类中添加属性

    Runtime 关联对象, 可在分类中添加属性 关联 API 如下 设置关联值 获取关联值 取消关联 关联策略

  • OC属性关联的实现原理

    OC中在分类中添加属性用属性关联技术来实现存取值的: 那么系统的属性关联功能是如何实现的呢? 属性关联怎么存储对象...

  • iOS 分类关联属性

    属性修饰关键字

  • 基础知识

    关联对象 分类中添加属性 NSMutableURLRequest NSURLRequestUsePortocolC...

  • 分类、继承、扩展

    ==分类== 是不能添加属性的,只能关联属性。属性包含 get,set ,成员变量,而分类里并没有可存储成员变量的...

  • Runtime为分类添加属性-2021-02-24-周三

    正常情况下,分类可以添加方法,但是不能添加属性;通过runtime的关联对象,可以实现分类添加属性的目的; 分类头...

  • 运行时运用

    一 , 设置关联属性 分类中设置属性进行关联判断(其中SDWebimage中用到过) 二, 运行时动态调用方法(...

  • 07.Objective-C 关联对象

    问题 分类中可以添加属性吗? 整么才能使分类中的属性,像正常类的属性一样使用? 关联对象的本质 答案 分类中可以添...

网友评论

      本文标题:分类的关联属性

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