_objc_init解析
在objc源码中看到调用_dyld_objc_notify_register前有几个初始化方法如下:
void _objc_init(void)
{
static bool initialized = false;
if (initialized) return;
initialized = true;
// fixme defer initialization until an objc-using image is found?
environ_init(); //环境变量设置
tls_init(); //创建线程的析构函数,tls线程的局部存储
static_init(); // 运行C++的静态构造函数,并且在dyld调用objc_init函数之前调用
runtime_init(); //分类表的初始化和类表的初始化
exception_init();//异常处理的初始化,如数组越界等异常
#if __OBJC2__
cache_t::init(); //缓存的初始化
#endif
_imp_implementationWithBlock_init();
_dyld_objc_notify_register(&map_images, load_images, unmap_image);
#if __OBJC2__
didCallDyldNotifyRegister = true;
#endif
}
environ_init
在environ_init方法中我们可以通过设置OBJC_HELP 和 OBJC_PRINT_OPTIONS,可以在XCode->product->scheme->edit scheme如下设置:
就会打印很多环境变量,环境变量说明:
load_images
- 懒加载类:没有重写load方法
- 非懒加载类:重写了load方法
load_images方法说明
prepare_load_methods方法
schedule_class_load方法
call_load_methods方法
结论
- load_imges是找到所有的load方法并且去执行;
- 先找本来的load方法,再找父类的load方法,最后找分类的load方法,所以先执行父类,在执行子类,最后执行分类;
- 在写load方法的时候不能写[super load],会自动执行父类load方法;
- 如果有多个分类中有load,会按照编译顺序去执行分类的load方法;
- load方法是直接调用;
- load方法是线程安全的;
map_images探索
map_images 进入map_images_nolock函数中
map_images_nolock说明
preopt_init()函数,共享缓存优化_objc_inform打印已经加载的image- 找到所有的类,可执行文件或者动态库都是以mach-o文件格式,是一堆的二进制数据,他们的头部都有一些配置文件,描述存储代码的位置大小,常量数据的位置大小,dyld从头部去读取,找到所有的类;
sel_init初始化C++的构造方法和析构方法;arr_init初始化自动释放池、散列表、关联对象的初始化_read_images
_read_images说明
- 开启non-pointer isa,指针优化开启,优化NSNumber等的tagged pointer优化,小对象优化,加载所有类到类的gdb_objc_realized_classes(dyld 共享缓存数据的表)表中。
- 对所有类做重映射。
- 将所有SEL都注册到namedSelectors表中。
- 修复函数指针遗留。
- 将所有Protocol都添加到protocol_map表中。
- 对所有Protocol做重映射。
- 初始化所有非懒加载的类,进行rw、ro等操作。
- 遍历已标记的懒加载的类,并做初始化操作。
- 处理所有Category,包括Class和Meta Class。
- 初始化所有未初始化的类。
readClass
在 discover classes中调用 readClass 方法 读取所有类并且调用addClassTableEntry 方法,加入到类表中;
可以加入如下方法,分辨自己的写的类:
初始化所有非懒加载的类
源码如下:
// Realize non-lazy classes (for +load methods and static instances)
for (EACH_HEADER) {
classref_t const *classlist = hi->nlclslist(&count);
for (i = 0; i < count; i++) {
Class cls = remapClass(classlist[i]);
if (!cls) continue;
addClassTableEntry(cls);
if (cls->isSwiftStable()) {
if (cls->swiftMetadataInitializer()) {
_objc_fatal("Swift class %s with a metadata initializer "
"is not allowed to be non-lazy",
cls->nameForLogging());
}
// fixme also disallow relocatable classes
// We can't disallow all Swift classes because of
// classes like Swift.__EmptyArrayStorage
}
realizeClassWithoutSwift(cls, nil);
}
}
ts.log("IMAGE TIMES: realize non-lazy classes");
realizeClassWithoutSwift
这个方法是-类的初始化操作,关键代码
- 给rw开辟空间,将ro中的数据‘拷贝’到rw中:
- 递归调⽤realizeClassWithoutSwift,对⽗类和元类进⾏初始化
supercls = realizeClassWithoutSwift(remapClass(cls->getSuperclass()), nil);
metacls = realizeClassWithoutSwift(remapClass(cls->ISA()), nil);
- 设置类的父类和isa指针
// Update superclass and metaclass in case of remapping
cls->setSuperclass(supercls);
cls->initClassIsa(metacls);
- 处理分类
// Attach categories
methodizeClass(cls, previously);
懒加载类的加载流程
懒加载类也会调用运行到realizeClassWithoutSwift方法中,当我们使用懒加载类中,我们才能看到他调用realizeClassWithoutSwift,第一次接受到消息的时候才会被加载;