本系列博客是本人的源碼閱讀筆記,如果有 iOS 開發者在看 runtime 的,歡迎大家多多交流。爲了方便討論,本人新建了一個微信羣(iOS技術討論羣),想要加入的,請添加本人微信:zhujinhui207407,【加我前請備註:ios 】,本人博客http://www.kyson.cn 也在不停的更新中,歡迎一起討論
本文完整版詳見筆者小專欄:https://xiaozhuanlan.com/runtime
概述
我們在iOS開發之runtime(27): _read_images 淺析中講解了 class 相關的多個 hash 表:
- gdb_objc_realized_classes
- remapped_class_map
- future_named_class_map
- nonmeta_class_map
本文我們就詳細的分析一下這幾個 hash map 的第一個: gdb_objc_realized_classes。
gdb_objc_realized_classes
gdb_objc_realized_classes is actually a list of named classes not in the dyld shared cache, whether realized or not.
這段文字出現在文件 objc_runtime_new.mm 中:
這裏翻譯一下:
gdb_objc_realized_classes 是一系列的類列表,這些類不管有沒有實現都不在 dyld 的共享緩存中。
全局搜索 gdb_objc_realized_classes,我們可以看到一系列方法,
這些方法涉及到對於 gdb_objc_realized_classes 的一系列操作,包括:
獲取某個類:
static Class getClass_impl(const char *name)
{
runtimeLock.assertLocked();
// allocated in _read_images
assert(gdb_objc_realized_classes);
// Try runtime-allocated table
Class result = (Class)NXMapGet(gdb_objc_realized_classes, name);
if (result) return result;
// Try table from dyld shared cache
return getPreoptimizedClass(name);
}
添加某個類:
/***********************************************************************
* addNamedClass
* Adds name => cls to the named non-meta class map.
* Warns about duplicate class names and keeps the old mapping.
* Locking: runtimeLock must be held by the caller
**********************************************************************/
static void addNamedClass(Class cls, const char *name, Class replacing = nil)
{
runtimeLock.assertWriting();
Class old;
if ((old = getClass(name)) && old != replacing) {
inform_duplicate(name, old, cls);
// getNonMetaClass uses name lookups. Classes not found by name
// lookup must be in the secondary meta->nonmeta table.
addNonMetaClass(cls);
} else {
NXMapInsert(gdb_objc_realized_classes, name, cls);
}
assert(!(cls->data()->flags & RO_META));
// wrong: constructed classes are already realized when they get here
// assert(!cls->isRealized());
}
移除某個類:
/***********************************************************************
* removeNamedClass
* Removes cls from the name => cls map.
* Locking: runtimeLock must be held by the caller
**********************************************************************/
static void removeNamedClass(Class cls, const char *name)
{
runtimeLock.assertWriting();
assert(!(cls->data()->flags & RO_META));
if (cls == NXMapGet(gdb_objc_realized_classes, name)) {
NXMapRemove(gdb_objc_realized_classes, name);
} else {
// cls has a name collision with another class - don't remove the other
// but do remove cls from the secondary metaclass->class map.
removeNonMetaClass(cls);
}
}
而初始化的位置就是我們所知道的 _read_images 方法中:
// namedClasses
// Preoptimized classes don't go in this table.
// 4/3 is NXMapTable's load factor
int namedClassesSize =
(isPreoptimized() ? unoptimizedTotalClasses : totalClasses) * 4 / 3;
gdb_objc_realized_classes =
NXCreateMapTable(NXStrValueMapPrototype, namedClassesSize);
add 方法的也位於 _read_images 調用棧中:
- void _objc_init(void)
- void _dyld_objc_notify_register();
- void map_2_images();
- void map_images_nolock();
- void _read_images();
- Class readClass();
- void addNamedClass();
需要注意的是:
addNamedClass(cls, mangledName, replacing);
的第二個參數是 mangledName, 也就是上一篇文章筆者 Demo 中給大家從 section 中獲取的數據。
現在看來,gdb_objc_realized_classes 的作用已經很明顯了,即是對所有的類進行緩存:從對應的 section 中讀取所有的類,取出來後以 mangledName 作爲鍵,以 class 結構體作爲值。
至此 gdb_objc_realized_classes 分析結束。