本系列博客是本人的源碼閱讀筆記,如果有 iOS 開發者在看 runtime 的,歡迎大家多多交流。
但大家心中的問題可能也接踵而至:
- 方法 _getObjc2NonlazyClassList 作用是什么?
- 什么是 remapped_class_map ?
- 什么時候 創建 remapped_class_map ?以及什么時候 addRemappedClass ?
分析
對于第一個問題,相信大家稍微 Google 一下就會有結果:
NonlazyClass is all about a class implementing or not a +load method.
All the classes implemented in a given image file have a reference in a list stored in the "__DATA, __objc_classlist, regular, no_dead_strip" binary's section. This list allows the runtime system to keep track of all the classes stored in such file. However, not all of the classes need to be realized when the program starts up. That's why when a class implements a +load method, it also has a reference in a list stored in the "__DATA, __objc_nlclslist, regular, no_dead_strip" section.
So, _getObjc2NonlazyClassList retrieves the list of classes that do implement a +load method and are so called non-lazy. _getObjc2ClassList retrieves a list of all the classes in a image file, including the classes that don't have a +load method (and are called lazy) and the non-lazy ones. Non-lazy classes must be realized when the program starts up. Lazy classes, on the other hand, don't need to be realized immediately. This may be delayed until the class receives a message for the first time, for example (that's the reason for them to be considered "lazy").
The same is true for categories, by the way.
以上引用來自:Objective-C: What is a lazy class?
也就是說,如果一個類實現了 +load 方法,那么它就是個 NonlazyClass。筆者為了證實這一點,做了個驗證:
// Realize non-lazy classes (for +load methods and static instances)
for (EACH_HEADER) {
classref_t *classlist =
_getObjc2NonlazyClassList(hi, &count);
for (i = 0; i < count; i++) {
Class cls = remapClass(classlist[i]);
//這里加了代碼用于測試
if (0 == strcmp(cls->mangledName(), "TestObject")) {
printf("TestObject is non-lazy Class\n");
fflush(stdout);
}
if (!cls) continue;
realizeClass(cls);
}
}
其中,TestObject 的定義如下:
@implementation TestObject
+(void) load {
}
int MyWeakLinkedFunction () {
return 1;
}
@end
那么,另外一個問題來了:
有多少 non-lazy class ?同樣的,筆者寫了如下代碼,打印出所有的 non-lazy class :
// Realize non-lazy classes (for +load methods and static instances)
for (EACH_HEADER) {
classref_t *classlist =
_getObjc2NonlazyClassList(hi, &count);
for (i = 0; i < count; i++) {
Class cls = remapClass(classlist[i]);
//這里加了代碼用于測試
printf("non-lazy Class:%s\n",cls->mangledName());
fflush(stdout);
if (!cls) continue;
realizeClass(cls);
}
}
打印的結果總結到筆者的GitHub了:non-lazy-classes.txt
可以看到,大概有60個 non-lazy-classes。
什么時候創建 remapped_class_map ?
其實函數
static NXMapTable *remappedClasses(bool create)
已經告訴我們了。
參數 create 告訴是否需要創建 hash map,在 _read_images 方法中傳進來的參數都是 NO,也就是說不會主動創建 hash map。我們全局搜索一下 remappedClasses,可以發現確實有地方調用的時候 傳入的參數是 YES:
static void addRemappedClass(Class oldcls, Class newcls) {
...
old = NXMapInsert(remappedClasses(YES), oldcls, newcls);
...
}
可以發現確實創建了,也就是我們前文所說的 addRemappedClass 方法。那
什么時候調用 addRemappedClass 方法?
但是并不是所有情況下都會調用到,只要查看一下函數 readClass 的實現就知道:
本文暫不做介紹了,后面的文章中會給大家介紹。
總結
本文終于又講完一個 hashmap:remapped_class_map。其實說白了很簡單,remapped_class_map 就是存儲了 non-lazy classes 的