iOS開發之 runtime(30) :none-lazy classes

本系列博客是本人的源碼閱讀筆記,如果有 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 的

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章