接上篇结尾,提到了类的实现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()
里