Runtime objc4-779.1 为什么不能向一个已存在的类添加成员变量?有什么办法达到相同的效果?
Posted Jsen_Wang
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Runtime objc4-779.1 为什么不能向一个已存在的类添加成员变量?有什么办法达到相同的效果?相关的知识,希望对你有一定的参考价值。
接上一篇博客继续
第二种方法
Func2 利用关联实现对已存在的类添加成员变量的效果
涉及两个主要的API
给某一个对象关联一个对象
objc_setAssociatedObject(id _Nonnull object, const void * _Nonnull key, id _Nullable value, objc_AssociationPolicy policy)
获取某一个对象的关联对象
id _Nullable objc_getAssociatedObject(id _Nonnull object, const void * _Nonnull key)
举个例子
objc_setAssociatedObject(self.father, "testKey", @"我是testKey的value", OBJC_ASSOCIATION_RETAIN);
NSLog(@"关联对象testKey的value:%@",objc_getAssociatedObject(self.father, "testKey"));
打印结果:2020-03-06 10:54:25.145628+0800 XSTest[30259:1297570] 关联对象testKey的value:我是testKey的value
用起来比较简单,API的具体用法百度即可,我们主要看,关联是如何实现的,我们一步步追溯objc_setAssociatedObject
后边的源码
Step1 objc-runtime.mm line 652
static void
_base_objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy)
_object_set_associative_reference(object, key, value, policy);
void
_object_set_associative_reference(id object, const void *key, id value, uintptr_t policy)
// 判空
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方便在后边hash表中的管理,它的作用就像是一个指针
DisguisedPtr<objc_object> disguised(objc_object *)object;
// 将需要关联的对象,封装成ObjcAssociation,方便管理
ObjcAssociation associationpolicy, value;
// 处理policy为retain和copy的修饰情况,
association.acquireValue();
// 获取关联对象管理者对象
AssociationsManager manager;
// 根据管理者对象获取对应关联表(HashMap)
AssociationsHashMap &associations(manager.get());
if (value)
// 如果这个disguised存在于ObjectAssociationMap()中,则替换,如果不存在则初始化后在插入
// 这里说明一下,我们关联的对象关系存在于ObjectAssociationMap中,而
// ObjectAssociationMap有多个,所以,这一步是对ObjectAssociationMap的一个管理,下边才是对我们要关联的对象的操作
auto refs_result = associations.try_emplace(disguised, ObjectAssociationMap);
// 如果这是此对象第一次被关联
if (refs_result.second)
// 修改isa_t中的has_assoc字段,标记其被关联状态
object->setHasAssociatedObjects();
// 这里才是对我们要关联的对象操作
auto &refs = refs_result.first->second;
// 想map中插入key value对
auto result = refs.try_emplace(key, std::move(association));
// 这里没有看懂,为什么没有第二个就要交换一下..
if (!result.second)
association.swap(result.first->second);
else
// value为空, 并且在associations中有记录,则进行擦除操作
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();
所以我们通过这个插入的代码可以看出来存储关联对象的是hash表,代码关系如下图所示
图是从http://www.cocoachina.com/cms/wap.php?action=article&id=23892转过来的,感谢作者,侵权删除
从数据结构和插入代码我们看出,之所以关联可以在运行时向已存在类中添加成员变量的原因是因为,被添加的成员变量实际并没有存储在类的内存中,而是在这个树状结构中的某一张hash表中以key value pair的形式存储, 获取也根据key获取, 所以, 它为什么可以给category添加成员变量也就能解释通了
以上是关于Runtime objc4-779.1 为什么不能向一个已存在的类添加成员变量?有什么办法达到相同的效果?的主要内容,如果未能解决你的问题,请参考以下文章
Runtime objc4-779.1 为什么不能向一个已存在的类添加成员变量?有什么办法达到相同的效果?
Runtime objc4-779.1 App启动过程中Runtime都干了什么?
Runtime objc4-779.1 OC中,为什么swizzleMethod时要先addMethod?
Runtime objc4-779.1 App启动过程中Runtime都干了什么?