在iOS App启动过程中,符号的加载是一个非常重要的过程。只有当完符号加载和绑定结束,安装包中的符号字符串真正与内存中地址才能一一对应,这是应用运行的前提和基础。
为了避免符号加载产生过多耗时,类相关的符号支持两种不同的加载方式:懒加载和非懒加载。
懒加载类
没有实现load方法,在第一次对其发送消息的时候(调用方法之前)才初始化。
这种设计的好处是可以减少启动工作量,降低启动时间。比如一个项目中有10000个类,没有必要在启动的时候就全部加载出来,因为这个时候根本不需要用到它。
非懒加载符号会在dyld加载时就在符号表中绑定真实的符号地址,绑定后的符号地址存储在nl_symbol_ptr。
非懒加载类
实现了load方法或者子类实现了load方法的类,会在App启动时就开始对其进行加载。
这主要是因为load方法会在App启动时被调用,而要调用其load方法,显然需要先对类进行加载。
懒加载的符号地址存储在__la_symbol_ptr,在编译时存储的统一为__stub_helper地址,只在符号被第一次调用后才会绑定真实的地址。
懒加载的符号第一次被访问时,会先跳转到__stub_helper, 然后在该位置调用dyld_stub_binder:执行符号绑定。绑定完成后,__la_symbol_ptr 存储的值会被修正为真正的函数地址。后续再调用对应符号时, 则会直接访问修正后的真实的函数地址。