美文网首页
分类-关联对象

分类-关联对象

作者: coder1003 | 来源:发表于2019-12-15 20:29 被阅读0次

给分类添加成员变量

另一篇:关联对象 AssociatedObject 完全解析
.h

#import <Foundation/Foundation.h>
@interface NSObject (Person)
@property (nonatomic, copy) NSString *name;
@end

.m

#import "NSObject+Person.h"
#import <objc/runtime.h> /*或者 #import <objc/message.h>*/
static NSString *nameKey = @"nameKey"; //那么的key

@interface NSObject ()
@end
@implementation NSObject (Person)
/**
 setter方法
 */
- (void)setName:(NSString *)name {
    objc_setAssociatedObject(self, &nameKey, name, OBJC_ASSOCIATION_COPY);
}
/**
 getter方法
 */
- (NSString *)name {
    return objc_getAssociatedObject(self, &nameKey);
}
@end

在其他实例中调用

- (void)viewDidLoad {
    NSObject *objc = [[NSObject alloc] init];
    objc.name = @"almost";
    NSLog(@"%@", objc.name);
}

关联策略是个枚举值,解释如下:

typedef OBJC_ENUM(uintptr_t, objc_AssociationPolicy) {
    OBJC_ASSOCIATION_ASSIGN = 0,             //关联对象的属性是弱引用    
    OBJC_ASSOCIATION_RETAIN_NONATOMIC = 1,   //关联对象的属性是强引用并且关联对象不使用原子性
    OBJC_ASSOCIATION_COPY_NONATOMIC = 3,     //关联对象的属性是copy并且关联对象不使用原子性
    OBJC_ASSOCIATION_RETAIN = 01401,         //关联对象的属性是copy并且关联对象使用原子性
    OBJC_ASSOCIATION_COPY = 01403            //关联对象的属性是copy并且关联对象使用原子性
};

关联对象本质

问: 可以用关联对象给分类添加成员变量, 那么关联对象保存在哪里?

  • 关联对象由AssociationsManager管理在AssocitionsHashMap存储
  • 所有关联对象的关联类容都在同一个全局容器中[所有分类的的关联对象都放在全局容器中]

源码:

id objc_getAssociatedObject(id object, const void *key) {
    return _object_get_associative_reference(object, (void *)key);
}

void objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy) {
    _object_set_associative_reference(object, (void *)key, value, policy);
}

void objc_removeAssociatedObjects(id object) 
{
    if (object && object->hasAssociatedObjects()) {
        _object_remove_assocations(object);
    }
}
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;
    {
        //关联对象管理, c++实现的一个类
        AssociationsManager manager;
        //是一个全局容器
        AssociationsHashMap &associations(manager.associations());
        disguised_ptr_t disguised_object = DISGUISE(object);
        if (new_value) {
            // break any existing association.
            //根据对象指针查找对应的一个ObjectAssociationMap结构的map
            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 {
//传value = nil,进入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);
}

截屏2019-12-15下午8.21.52.png
  • 根据图中由下往上
  1. 首先, 传入value("hello")和policy(OBJC_ASSOCIATION_COPY_NONATOMIC)封装成一个ObjcAssocation这样一个结构
  2. 再把ObjcAssocation和selector的key(text) 建立一个映射结构ObjcAssocationMap
  3. 最后把ObjcAssocationMap作为全局容器AssocationHashMap的一个value, 对应的key是DISGIUISE(obj)

相关文章

  • OC语言之category_关联对象的本质源码解析

    关联对象 能否给分类添加"成员变量"? 使用关联对象技术为分类添加"成员变量" 关联对象添加的"成员变量"添加到了...

  • 分类-关联对象

    给分类添加成员变量 另一篇:关联对象 AssociatedObject 完全解析.h .m 在其他实例中调用 关联...

  • 12.2.类分类

    分类.h文件: 分类.m文件: 关联对象

  • Objective - C 关联对象(二) 关联对象的底层数据结

    (一)分类 - 关联对象的原理 实现关联对象技术的核心对象有: AssociationsManager Assoc...

  • iOS Objective-C 关联对象

    iOS Objective-C 关联对象 1. 关联对象简介 对于关联对象,我们熟悉它的地方就是给分类添加属性。虽...

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

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

  • iOS原理篇(四):关联对象

    关联对象的使用场合 关联对象的基本使用 关联对象的底层原理 一、关联对象的使用场合默认情况下,因为分类底层结构的限...

  • 基础知识

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

  • OC关联对象源码解析

    OC关联对象源码解析 默认情况下分类是不能添加成员变量的,我们可以利用Runtime通过关联对象间接实现给分类添加...

  • 关联对象

    在分类中不能添加属性,但是却可以使用 关联对象的方式,给类添加变量。主要重点是: 关联对象的实现方式。 关联对象散...

网友评论

      本文标题:分类-关联对象

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