iOS程序加载过程
- 在程序启动之后,由dyld(动态链接编辑器)将程序加载到二进制中,完成一些文件的初始化操作。
- Runtime向dyld中注册回调函数。
- 通过ImageLoader将所有的image加载到内存中。
- dyld在images发生改变时主动调用回调函数。
- Runtime在接收到回调函数后开始执行map_images,load_images等函数,并回调+load函数。
- 调用main()函数,开始执行业务代码。
map_images
在Runtime加载过程中,会调用_objc_init函数,在_objc_init函数中主要调用了map_images,load_images等方法
void _objc_init(void) {
// .... 各种init
_dyld_objc_notify_register(&map_images, load_images, unmap_image);
}
//主要作用是一个调用中转
void map_images(unsigned count, const char * const paths[], const struct mach_header * const mhdrs[])
{
rwlock_writer_t lock(runtimeLock);
return map_images_nolock(count, paths, mhdrs);
}
void map_images_nolock(unsigned mhCount, const char * const mhPaths[],
const struct mach_header * const mhdrs[])
{
if (hCount > 0) {
_read_images(hList, hCount, totalClasses, unoptimizedTotalClasses);
}
}
read_images主要逻辑:
- 加载所有类到gbd_objc_readlized_classes表中
- 对所有类做重映射
- 将所有SEL都注册到namedSelectors表中
- 修复函数指针遗留
- 将所有的Protocol都添加到protocol_map表中
- 多所有的Protocol做重映射
- 初始化所有非懒加载的类,进行rw,ro操作
- 遍历已标记的懒加载的类,并做初始化操作
- 处理所有Category,包括Class和Meta Class
- 初始化所有未初始化的类
void _read_images(header_info **hList, uint32_t hCount, int totalClasses, int unopt imizedTotalClasses)
{
header_info *hi;
uint32_t hIndex;
size_t count;
size_t i;
Class *resolvedFutureClasses = nil;
size_t resolvedFutureClassCount = 0;
static bool doneOnce;
TimeLogger ts(PrintImageTimes);
#define EACH_HEADER \
hIndex = 0; \
hIndex < hCount && (hi = hList[hIndex]); \
hIndex++
if (!doneOnce) {
doneOnce = YES;
//实例化存储类的哈希表,并根据当前类数量做动态扩容
int namedClassesSize = (isPreoptimized() ? unoptimizedTotalClasses : totalClasses) * 4 / 3;
gdb_objc_realized_classes = NXCreateMapTable(NXStrValueMapPrototype, namedClassesSize);
}
//由编辑器读取类列表,并将所有的类添加到哈希表中,并标记懒加载的类并初始化空间
for (EACH_HEADER) {
if (! mustReadClasses(hi)) {
continue;
}
bool headerIsBundle = hi->isBundle();
bool headerIsPreoptimized = hi->isPreoptimized();
/** 将新类添加到哈希表中 */
// 从编译后的类列表中取出所有类,获取到一个classref_t类型指针
classref_t *classlist = _getObjc2ClassList(hi, &count);
for (i = 0; i < count; i++) {
// 数组中取出OS_dispatch_queue_concurrent、OS_xpc_object、NSRunLoop等系统类<CF、Fundation、liddispatch等>和自己创建的类
Class cls = (Class)classlist[i];
// 通过readClass函数获取处理过后的新类,内部主要操作ro和rw结构体
Class newCls = readClass(cls, headerIsBundle, headerIsPreoptimized);
// 初始化所有懒加载的类需要的内存空间
if (newCls != cls && newCls) {
// 将懒加载的类添加到数组中
resolvedFutureClasses = (Class *)realloc(resolvedFutureClasses, (resolvedFutureClassCount+1) * sizeof(Class));
resolvedFutureClasses[resolvedFutureClassCount++] = newCls;
}
}
}
//将为映射的Class和superClass重映射,被remap的类都是非懒加载的类
if (!noClassesRemapped()) {
for (EACH_HEADER) {
// 重映射Class,从_getObjc2ClassRefs函数中取出类的引用
Class *classrefs = _getObjc2ClassRefs(hi, &count);
for (i = 0; i < count; i++) {
remapClassRef(&classrefs[i]);
}
}
// 重映射父类
classrefs = _getObjc2SuperRefs(hi, &count);
for (i = 0; i < count; i++) {
remapClassRef(&classrefs[i]);
}
}
// 对SEL做重映射
static size_t UnfixedSelectors; sel_lock();
for (EACH_HEADER) {
if (hi->isPreoptimized()) continue;
bool isBundle = hi->isBundle();
SEL *sels = _getObjc2SelectorRefs(hi, &count); UnfixedSelectors += count;
for (i = 0; i < count; i++) {
const char *name = sel_cname(sels[i]);
//注册SEL
sels[i] = sel_registerNameNoLock(name, isBundle);
}
}
// 修复旧的函数指针遗留
for (EACH_HEADER) {
message_ref_t *refs = _getObjc2MessageRefs(hi, &count);
if (count == 0) continue;
for (i = 0; i < count; i++) {
// 在内部将常用的alloc、objc_msgSend等函数指针进行注册,并fix为新的函数指针
fixupMessageRef(refs+i);
}
}
// 遍历所有协议列表,并且将协议列表加载到Protocol的哈希表中
for (EACH_HEADER) {
extern objc_class OBJC_CLASS_$_Protocol;
// cls = Protocol类,所有协议和对象的结构体都类似,isa对应Protocol类
Class cls = (Class)&OBJC_CLASS_$_Protocol;
assert(cls);
// 获取protocol哈希表
NXMapTable *protocol_map = protocols();
bool isPreoptimized = hi->isPreoptimized();
bool isBundle = hi->isBundle();
// 从编译器中读取并初始化Protocol
protocol_t **protolist = _getObjc2ProtocolList(hi, &count);
for (i = 0; i < count; i++) {
readProtocol(protolist[i], cls, protocol_map,
isPreoptimized, isBundle);
}
}
// 修复协议列表应用,优化后的images不确定正确与否
for (EACH_HEADER) {
//下面的_getObjc2ProtocolRefs函数与上面的_getObjc2ProtocolRefs不同
protocol_t **protolist = _getObjc2ProtocolRefs(hi, &count);
for (i = 0; i < count; i++) {
remapProtocolRef(&protolist[i]);
}
}
// 实现非懒加载的类
for (EACH_HEADER) {
classref_t *classlist =
_getObjc2NonlazyClassList(hi, &count);
for (i = 0; i < count; i++) {
Class cls = remapClass(classlist[i]);
if (!cls) continue;
//实现非来加载的类(实例化一些信息,如rw)
realizeClass(cls);
}
}
// 遍历resolvedFutureClasses数组,实现所有懒加载的类
if (resolvedFutureClasses) {
for (i = 0; i < resolvedFutureClassCount; i++) {
// 实现懒加载的类
realizeClass(resolvedFutureClasses[i]); resolvedFutureClasses[i]->setInstancesRequireRawIsa(false/*inherited*/);
}
free(resolvedFutureClasses);
}
// 发现和处理所有Category
for (EACH_HEADER) {
// 外部循环遍历找到当前类,查找类对应的Category数组
category_t **catlist = _getObjc2CategoryList(hi, &count);
bool hasClassProperties = hi->info()->hasCategoryClassProperties();
内部循环遍历当前类的所有的Category
for (i = 0; i < count; i++) {
category_t *cat = catlist[i];
Class cls = remapClass(cat->cls);
// 首先,通过所属的类注册Category。如果这个类已经被实现,则重新构造类的方法列表
bool classExists = NO;
if (cat->instanceMethods || cat->protocols || cat->instanceProperties) {
// 将Category添加到对应的value中,value是Class对应的所有的Category数组
addUnattachedCategoryForClass(cat, cls, hi);
// 将Category的method,protocol,property添加到Class中
if (cls->isRealized()) {
remethodizeClass(cls);
classExists = YES;
}
}
// 与下面逻辑相同,不过是在Meta Class中进行操作
if (cat->classMethods || cat->protocols || (hasClassProperties && cat->_classProperties)) {
addUnattachedCategoryForClass(cat, cls->ISA(), hi);
if (cls->ISA()->isRealized()) {
remethodizeClass(cls->ISA());
}
}
}
}
// 初始化所有的类,Category必须是最后执行
// DebugNonFragileIvars = -1,不执行
if (DebugNonFragileIvars) {
realizeAllClasses();
}
#undef EACH_HEADER
}
load_images
void load_images(const char *path __unused, const struct mach_header *mh) {
// Return without taking locks if there are no +load methods here.
if (!hasLoadMethods((const headerType *)mh)) return;
recursive_mutex_locker_t lock(loadMethodLock);
// Discover load methods
{
mutex_locker_t lock2(runtimeLock);
//主要查找Class、Category的方法方法
prepare_load_methods((const headerType *)mh);
}
// Call +load methods (without runtimeLock - re-entrant)
// 调用Class、Category的方法列表
call_load_methods();
}
void prepare_load_methods(const headerType *mhdr) {
size_t count, i;
runtimeLock.assertLocked();
// 获取到非懒加载类的列表
classref_t *classlist = _getObjc2NonlazyClassList(mhdr, &count);
for (i = 0; i < count; i++) {
// 设置Class的调用列表
schedule_class_load(remapClass(classlist[i]));
}
// 获取Category的列表
category_t **categorylist = _getObjc2NonlazyCategoryList(mhdr, &count);
for (i = 0; i < count; i++) {
category_t *cat = categorylist[i];
Class cls = remapClass(cat->cls);
// category for ignored weak-linked class,忽略弱链接<不懂>的类别
if (!cls) continue;
// 实例化所属的类
realizeClass(cls);
assert(cls->ISA()->isRealized());
// 设置Categoty的调用列表
add_category_to_loadable_list(cat);
}
}
static void schedule_class_load(Class cls) {
if (!cls) return;
// _read_images should realize,_read_images是否完成
assert(cls->isRealized());
// 已经添加完成,则return
if (cls->data()->flags & RW_LOADED) return;
// Ensure superclass-first ordering,确保superClass添加
schedule_class_load(cls->superclass);
// 添加imp、class到调用中
add_class_to_loadable_list(cls);
// 设置class的标识符,表示已添加到list中
cls->setInfo(RW_LOADED);
}
// 在obj-loadmethod.mm中
void add_category_to_loadable_list(Category cat) {
IMP method;
// 获取Category中Load方法的imp
loadMethodLock.assertLocked();
method = _category_getLoadMethod(cat);
// Don't bother if cat has no +load method,没有则return
if (!method) return;
if (PrintLoading) {
_objc_inform("LOAD: category '%s(%s)' scheduled for +load",
_category_getClassName(cat), _category_getName(cat));
}
如果已使用大小等于数组大小,对数组进行动态扩容
if (loadable_categories_used == loadable_categories_allocated) {
loadable_categories_allocated = loadable_categories_allocated*2 + 16;
loadable_categories = (struct loadable_category *)
realloc(loadable_categories,loadable_categories_allocated * sizeof(struct loadable_category));
}
loadable_categories[loadable_categories_used].cat = cat;
loadable_categories[loadable_categories_used].method = method;
loadable_categories_used++;
}
// 准备好了loadable_calss、loadable_categories数组,load_images会通过call_load_methods函数执行这些load方法
void call_load_methods(void) {
static bool loading = NO;
bool more_categories;
loadMethodLock.assertLocked();
// Re-entrant calls do nothing; the outermost call will finish the job.防止重新进入
if (loading) return;
loading = YES;
void *pool = objc_autoreleasePoolPush();
do {
// 1. Repeatedly call class +loads until there aren't any more
while (loadable_classes_used > 0) {
call_class_loads();
}
// 2. Call category +loads ONCE
more_categories = call_category_loads();
// 3. Run more +loads if there are classes OR more untried categories
} while (loadable_classes_used > 0 || more_categories);
objc_autoreleasePoolPop(pool);
loading = NO;
}
// 通过遍历获得loadable_class结构体
static void call_class_loads(void) {
int i;
// Detach current loadable list.
struct loadable_class *classes = loadable_classes;
int used = loadable_classes_used;
loadable_classes = nil;
loadable_classes_allocated = 0;
loadable_classes_used = 0;
// Call all +loads for the detached list.
for (i = 0; i < used; i++) {
Class cls = classes[i].cls;
load_method_t load_method = (load_method_t)classes[i].method;
if (!cls) continue;
if (PrintLoading) {
_objc_inform("LOAD: +[%s load]\n", cls->nameForLogging());
}
(*load_method)(cls, SEL_load);
}
// Destroy the detached list.
if (classes) free(classes);
}
struct loadable_class {
Class cls; // may be nil
IMP method;
};
- 通过上述代码,发现load方法的调用顺序为 父类 -> 子类 -> Category。
- category的 load方法会覆盖 class的 load方法