本系列博客是本人的源碼閱讀筆記,如果有 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 中插入數據。這裏畫一幅圖加深理解:
以上這張圖已經說明了之前筆者分析的兩個 map 與本文的 map 之間的關係。
總結
future named class 的介紹就到這裏了,希望大家有所收穫。其實筆者看來,不管是上一篇文章的 remapped_class_map 還是本文的 future_named_class_map 裏面的數據都是空。remapped_class_map 有數據是需要一定條件,而 future_named_class_map 有數據也是需要先 add 的,所以大家對於這兩個 map 只需要有個大概的概念就好,後面如果真的碰到他們有數據,我們在詳細分析。