本系列博客是本人的源码阅读笔记,如果有 iOS 开发者在看 runtime 的,欢迎大家多多交流。为了方便讨论,本人新建了一个微信群(iOS技术讨论群),想要加入的,请添加本人微信:zhujinhui207407,【加我前请备注:ios 】,本人博客http://www.kyson.cn 也在不停的更新中,欢迎一起讨论
本文完整版详见笔者小专栏:https://xiaozhuanlan.com/runtime
前言
在前面的文章中我们分析过,存储在 hash map 中数据的几个类:
- gdb_objc_realized_classes:已经实现过的类列表
- remapped_class_map,已经重映射的类列表
今天我们就讲另外一个和上面两个息息相关的 hash map :future_named_class_map,它存储了 ”未来“要实现的类?这里先卖个关子,等笔者先将其分析一下再说:
创建
static NXMapTable *future_named_class_map = nil;
static NXMapTable *futureNamedClasses()
{
runtimeLock.assertWriting();
if (future_named_class_map) return future_named_class_map;
// future_named_class_map is big enough for CF's classes and a few others
future_named_class_map = NXCreateMapTable(NXStrValueMapPrototype, 32);
return future_named_class_map;
}
以上代码清晰明了:如果有的话使用,没有的话则创建。
获取
OBJC_EXPORT Class objc_getFutureClass(const char *name)
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0)
OBJC_ARC_UNAVAILABLE;
这个方法需要注意,它是在 runtime.h 中声明的,也就是说,他其实是对外暴露的,可以直接使用,不过看其注释:
/*** Used by CoreFoundation's toll-free bridging.
Return the id of the named class.
@return The id of the named class, or an uninitialized class
structure that will be used for the class when and if it does
get loaded.
@warning Do not call this function yourself.
***/
注意最后一句: 不要主动调用这个函数!
我们来看一下这个函数的实现:
Class objc_getFutureClass(const char *name)
{
Class cls;
cls = look_up_class(name, YES, NO);
if (cls) {
if (PrintFuture) {
_objc_inform("FUTURE: found %p already in use for %s",
(void*)cls, name);
}
return cls;
}
return _objc_allocateFutureClass(name);
}
其中函数 look_up_class 这里先不多做介绍了,里面逻辑较多,而且不是这个函数的重点,重点是最后一句:_objc_allocateFutureClass(name)
它才是从 hash map 中获取对应值的函数,其实现如下 :
Class _objc_allocateFutureClass(const char *name)
{
rwlock_writer_t lock(runtimeLock);
Class cls;
NXMapTable *map = futureNamedClasses();
if ((cls = (Class)NXMapGet(map, name))) {
// Already have a future class for this name.
return cls;
}
cls = _calloc_class(sizeof(objc_class));
addFutureNamedClass(name, cls);
return cls;
}
很容易理解:有的话就通过方法 NXMapGet 取出来,没有的话则创建。
移除
static Class popFutureNamedClass(const char *name)
{
runtimeLock.assertWriting();
Class cls = nil;
if (future_named_class_map) {
cls = (Class)NXMapKeyFreeingRemove(future_named_class_map, name);
if (cls && NXCountMapTable(future_named_class_map) == 0) {
NXFreeMapTable(future_named_class_map);
future_named_class_map = nil;
}
}
return cls;
}
这个方法有点熟悉了,正是上文介绍的 remap 的条件之一。上一篇文章讲述的是第一个条件,本文讲的是第二个条件。这两个条件无论哪一个符合都会调用方法:addRemappedClass,即向 remapped_class_map 中插入数据。这里画一幅图加深理解:
maps 之间关系
以上这张图已经说明了之前笔者分析的两个 map 与本文的 map 之间的关系。
总结
future named class 的介绍就到这里了,希望大家有所收获。其实笔者看来,不管是上一篇文章的 remapped_class_map 还是本文的 future_named_class_map 里面的数据都是空。remapped_class_map 有数据是需要一定条件,而 future_named_class_map 有数据也是需要先 add 的,所以大家对于这两个 map 只需要有个大概的概念就好,后面如果真的碰到他们有数据,我们在详细分析。
网友评论