接上篇結尾,提到了類的實現realizeClassWithoutSwift
,那麼realizeClassWithoutSwift
內部幹了些什麼?c++
下載objc818可調試源碼git
也在該函數內也添加if
判斷代碼,只查看該函數處理LGPerson
的實現,方便調試github
猜測方法列表應該在methodizeClass
處理算法
將sel
添加到方法列表markdown
按照地址進行排序函數
添加未排序前打印和排序後打印oop
通過prepareMethodLists
一系列處理後,查看ro
方法列表post
仍是沒有數據,因此目前方法還沒加到類裏面去。測試
methodizeClass
方法裏面ui
rwe
是什麼?可參看這篇文章,怎麼拿到rwe
?
全局搜索extAllocIfNeeded
,有多處使用extAllocIfNeeded
給rwe
賦值,如:
attachCategories
demangledName
class_setVersion
addMethods_finish
class_addProtocol
_class_addProperty
objc_duplicateClass
因此rwe
必然有值。
採用反推法 全局搜索attachCategories
調用的位置:
attachToClass
load_categories_nolock
全局搜索attachToClass
調用的位置:
methodizeClass
當previously
爲true
的時候,才能調用判斷條件裏面的attachToClass
方法。 previously
是methodizeClass
的參數
static void methodizeClass(Class cls, Class previously) 複製代碼
全局搜索methodizeClass
調用的位置:
realizeClassWithoutSwift
previously
也是realizeClassWithoutSwift
的參數 全局搜索realizeClassWithoutSwift
調用的位置發現 previously
爲nil
做爲參數,因此上圖中的方法不會調用。那麼久來到了:
全局搜索load_categories_nolock
loadAllCategories
_read_images
瞭解了attachCategories
被調起的流程,那麼來看看attachCategories
內部怎麼實現的
分類和類搭配加載有如下四種狀況。如今對這四種狀況分別分析。 目標是在加載主類後,查看ro
裏面有沒有分類數據,若是有分類數據,就說明分類加載有可能在編譯以前就完成。
調用順序: _read_images
非懶加載類> realizeClassWithoutSwift
>methodizeClass
>attachToClass
>load_categories_nolock
>attachCategories
>
調用順序:_read_images
非懶加載類 > realizeClassWithoutSwift
> methodizeClass
> attachToClass
注意:沒有調用
attachCategories
調用順序:_read_images
非懶加載類 > realizeClassWithoutSwift
> methodizeClass
> attachToClass
注意:也沒有調用
attachCategories
什麼都不會調用,對象第一次發送消息後纔會有調用。
當前以主類和分類都有load
方法爲例 測試代碼:
@interface LGPerson : NSObject
@property (nonatomic, copy) NSString *name;
- (void)personFunc;
@end
@implementation LGPerson
//更具狀況添加或刪除
+ (void)load{}
- (void)saySomething{
NSLog(@"%s",__func__);
}
@end
複製代碼
@interface LGPerson (LGA)
@property (nonatomic, copy) NSString *cateA_name;
- (void)cateFunc;
@end
@implementation LGPerson (LGA)
//更具狀況添加或刪除
+ (void)load{}
- (void)cateFunc{
NSLog(@"%s",__func__);
}
@end
複製代碼
在realizeClassWithoutSwift
中
mlist
地址存到mlists
中了
補充測試代碼:
@interface LGPerson (LGB)
- (void)cateFuncB;
@end
@implementation LGPerson (LGB)
//更具狀況添加或刪除
+ (void)load{}
- (void)cateFuncB{
NSLog(@"%s",__func__);
}
@end
複製代碼
流程跟蹤:
在 dyld
的時候已經合到一塊兒了,存在data()
裏面
在 dyld
的時候已經合到一塊兒了,存在data()
裏面
都沒有實現會推遲到第一次消息發送的時候進行初始化,它們的方法都已經加載到data
裏面了。
1.在main.m
中添加分類代碼
#import <Foundation/Foundation.h>
#import "LGPerson.h"
#import <objc/runtime.h>
@interface LGPerson (LG) <NSObject> @property (nonatomic, copy) NSString *cate_name;
@property (nonatomic, assign) int cate_age;
- (void)cate_instanceMethod1;
- (void)cate_instanceMethod2;
+ (void)cate_classMethod3;
@end
@implementation LGPerson (LG) - (void)cate_instanceMethod1{
NSLog(@"%s",__func__);
}
- (void)cate_instanceMethod2{
NSLog(@"%s",__func__);
}
+ (void)cate_classMethod3{
NSLog(@"%s",__func__);
}
@end int main(int argc, const char * argv[]) {
@autoreleasepool {
LGPerson *p = [LGPerson alloc];
[p cate_instanceMethod2];
NSLog(@"Hello, World!");
}
return 0;
}
複製代碼
3.將main.m
編譯成c++
文件
clang -rewrite-objc main.m -o main.cpp
複製代碼
_category_t
分類結構體結構
方法列表裏面卻卻沒有get
和set
方法,因此分類添加屬性須要本身實現get
和set
方法關聯對象
是否是懶加載類:當前類是否實現load
方法
map_images
的時候加載全部的數據:map_images
>map_images_nolock
> _read_images
>readClass
>_getObjc2ClassList
>realizeClassWithoutSwift
>methodizeClass
lookUpImpOrForward
>initializeAndMaybeRelock
>realizeClassMaybeSwiftMaybeRelock
>realizeClassWithoutSwift
>methodizeClass
load
方法macho
裏讀取的,若是其實現load
方法,就會調用attachCategories
,進行一系列的計算,因此load
方法耗時。load
方法,方法會在dyld
的時候加載並存到data()
裏