剖析iOS类加载流程(下)
2023-12-21 07:52:30
前言
在上一篇文章《iOS类加载流程分析(上)》中,我们已经探讨了ObjC源码中read_images函数一半的代码流程,所有本篇文章将对其下半部分的代码流程进行探究与分析。
学习重点
- _read函数
- imp_lookup函数
- load_images函数
- _objc_enter_runtime函数
_read函数
_read函数是ObjC类加载的核心函数,它负责从Mach-O文件中读取Objective-C类和协议的信息。_read函数的调用过程如下:
- (BOOL)readImages:(const char **)images count:(unsigned int)count
{
BOOL success = YES;
for (unsigned int i = 0; i < count; i++) {
success &= _read(images[i]);
}
return success;
}
从代码中可以看到,_read函数首先遍历所有需要加载的Mach-O文件,然后依次调用_read函数来读取每个Mach-O文件中的Objective-C类和协议的信息。
_read函数的实现如下:
- (BOOL)_read:(const char *)imagePath
{
// ...
// 省略一些代码
// ...
struct mach_header_64 header;
int fd = open(imagePath, O_RDONLY);
if (fd == -1) {
return NO;
}
if (read(fd, &header, sizeof(header)) != sizeof(header)) {
return NO;
}
close(fd);
// ...
// 省略一些代码
// ...
return YES;
}
_read函数首先打开指定的Mach-O文件,然后读取Mach-O文件头。如果文件头读取成功,_read函数会继续解析Mach-O文件中的Objective-C类和协议信息。
imp_lookup函数
imp_lookup函数是ObjC运行时用来查找指定方法的实现的函数。imp_lookup函数的调用过程如下:
- (IMP)imp_lookup:(SEL)aSelector inClass:(Class)aClass
{
// ...
// 省略一些代码
// ...
IMP imp = NULL;
// ...
// 省略一些代码
// ...
return imp;
}
从代码中可以看到,imp_lookup函数首先尝试从aClass的父类中查找aSelector方法的实现。如果在父类中找不到,则会尝试从aClass的元类中查找。如果在元类中也找不到,则会尝试从aClass的实现类中查找。如果在实现类中也找不到,则会尝试从aClass的分类中查找。如果在分类中也找不到,则会返回NULL。
load_images函数
load_images函数是ObjC运行时用来加载所有Objective-C类的函数。load_images函数的调用过程如下:
- (void)load_images
{
// ...
// 省略一些代码
// ...
struct mach_header_64 header;
// ...
// 省略一些代码
// ...
unsigned int count = 0;
const char **images = _dyld_image_paths(&count);
// ...
// 省略一些代码
// ...
BOOL success = [self readImages:images count:count];
// ...
// 省略一些代码
// ...
}
从代码中可以看到,load_images函数首先获取所有需要加载的Mach-O文件的路径,然后调用readImages函数来加载这些Mach-O文件中的Objective-C类和协议的信息。
_objc_enter_runtime函数
_objc_enter_runtime函数是ObjC运行时用来进入运行时的函数。_objc_enter_runtime函数的调用过程如下:
- (void)_objc_enter_runtime
{
// ...
// 省略一些代码
// ...
// 注册Objective-C类和协议
_class_register(&_objc_class);
_class_register(&_objc_protocol);
// ...
// 省略一些代码
// ...
}
从代码中可以看到,_objc_enter_runtime函数首先将Objective-C类和协议注册到运行时。然后,_objc_enter_runtime函数会执行一些其他初始化操作,例如初始化Objective-C运行时的垃圾回收器。
总结
本文对ObjC源码中read_images函数的下半部分代码流程进行了分析。我们探讨了_read函数、imp_lookup函数、load_images函数和_objc_enter_runtime函数等关键函数的实现和功能。通过对这些函数的分析,我们对iOS类加载流程有了更深入的了解。