1.入口
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;//这个时候所有类和分类应该已加载完成,如果没有直接return
recursive_mutex_locker_t lock(loadMethodLock);
// Discover load methods
{
mutex_locker_t lock2(runtimeLock);
prepare_load_methods((const headerType *)mh);//处理类与分类中的+load并存储到数据结构中
}
// Call +load methods (without runtimeLock - re-entrant)
call_load_methods();
}
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();//根据prepare_load_methods存储的类名和IMP,调用
}
// 2. Call category +loads ONCE
more_categories = call_category_loads();//分类的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;
}
load_images分类入口、call_load_methods分类载入方法、call_class_loads是类的load方法加载、call_category_loads分类的load方法加载。
可见:类的+load()加载优先于分类的+load加载,分类的+load方法与类的+load方法是独立的。
2. 加载准备
prepare_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++) {
/*
remapClass(classlist[i])缓存中找到对应的class实例
schedule_class_load 查找class对应的+load方法并存储在add_class_to_loadable_list中,递归优先处理父类的+load方法
*/
schedule_class_load(remapClass(classlist[i]));
}
//整体与上面类似
category_t **categorylist = _getObjc2NonlazyCategoryList(mhdr, &count);
for (i = 0; i < count; i++) {
category_t *cat = categorylist[i];
Class cls = remapClass(cat->cls);
if (!cls) continue; // category for ignored weak-linked class
realizeClass(cls);
assert(cls->ISA()->isRealized());
add_category_to_loadable_list(cat);
}
}
static void schedule_class_load(Class cls)
{
if (!cls) return;
assert(cls->isRealized()); // _read_images should realize:此时所有的类已实现
if (cls->data()->flags & RW_LOADED) return;
//解决了为什么父类的+load会先调用
// Ensure superclass-first ordering
schedule_class_load(cls->superclass);//递归处理父类class的load方法
add_class_to_loadable_list(cls);//load存储到loadable_classes数组中
cls->setInfo(RW_LOADED); //设置+load已加载标志位
}
void add_class_to_loadable_list(Class cls)
{
IMP method;
loadMethodLock.assertLocked();
method = cls->getLoadMethod();//如果有+load方法,返回对应的imp
if (!method) return; // Don't bother if cls has no +load method
if (PrintLoading) {
_objc_inform("LOAD: class '%s' scheduled for +load",
cls->nameForLogging());
}
if (loadable_classes_used == loadable_classes_allocated) {
loadable_classes_allocated = loadable_classes_allocated*2 + 16;
loadable_classes = (struct loadable_class *)
realloc(loadable_classes,
loadable_classes_allocated *
sizeof(struct loadable_class));
}
loadable_classes[loadable_classes_used].cls = cls;
loadable_classes[loadable_classes_used].method = method;
loadable_classes_used++;
}
void add_category_to_loadable_list(Category cat)
{
IMP method;
loadMethodLock.assertLocked();
method = _category_getLoadMethod(cat);
// Don't bother if cat has no +load method
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++;
}
- prepare_load_methods分两段:第一段先加载类的+load方法;
- _getObjc2NonlazyClassList:读取未加载的类的信息;
- schedule_class_load: 递归处理cls->superclass的load方法,确保父类中的+load能被正常加载。
- add_class_to_loadable_list:cls中的+load方法被添加到loadable_classes中;
这一段可以看出,父类的+load方法调用优先于子类的+load方法;+load和cls存储在loadable_categories,为后面加载+load方法做准备。
- 第二段加载分类中的+load方法
- add_category_to_loadable_list:分类的cls和+load方法存储到静态数组loadable_categories中
分类与类的是分开存储静态数组中的,所以+load方法不存在覆盖。
3.类方法加载
static void call_class_loads(void)
{
int i;
// Detach current loadable list.
//loadable_classes:prepare_load_methods存储的数据结构
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;//对应的cls
load_method_t load_method = (load_method_t)classes[i].method;//方法对应的IMP
if (!cls) continue;
if (PrintLoading) {
_objc_inform("LOAD: +[%s load]\n", cls->nameForLogging());
}
//调用cls对应的load:load_method是IMP,cls和SEL_load是方法参数
(*load_method)(cls, SEL_load);
}
// Destroy the detached list.
if (classes) free(classes);
}
- 遍历loadable_classes方法,调用cls的SEL_load方法。
4.分类方法加载
call_category_loads
static bool call_category_loads(void)
{
int i, shift;
bool new_categories_added = NO;
// Detach current loadable list.
struct loadable_category *cats = loadable_categories;
int used = loadable_categories_used;
int allocated = loadable_categories_allocated;
loadable_categories = nil;
loadable_categories_allocated = 0;
loadable_categories_used = 0;
// Call all +loads for the detached list.
for (i = 0; i < used; i++) {
Category cat = cats[i].cat;
load_method_t load_method = (load_method_t)cats[i].method;
Class cls;
if (!cat) continue;
cls = _category_getClass(cat);
if (cls && cls->isLoadable()) {
if (PrintLoading) {
_objc_inform("LOAD: +[%s(%s) load]\n",
cls->nameForLogging(),
_category_getName(cat));
}
(*load_method)(cls, SEL_load);
cats[i].cat = nil;//分类去了,只有IMP
}
}
// Compact detached list (order-preserving)
// 处理多个分类?
shift = 0;
for (i = 0; i < used; i++) {
if (cats[i].cat) {
cats[i-shift] = cats[i];
} else {
shift++;
}
}
used -= shift;
// Copy any new +load candidates from the new list to the detached list.
new_categories_added = (loadable_categories_used > 0);
for (i = 0; i < loadable_categories_used; i++) {
if (used == allocated) {
allocated = allocated*2 + 16;
cats = (struct loadable_category *)
realloc(cats, allocated *
sizeof(struct loadable_category));
}
cats[used++] = loadable_categories[i];
}
// Destroy the new list.
if (loadable_categories) free(loadable_categories);
// Reattach the (now augmented) detached list.
// But if there's nothing left to load, destroy the list.
if (used) {
loadable_categories = cats;
loadable_categories_used = used;
loadable_categories_allocated = allocated;
} else {
if (cats) free(cats);
loadable_categories = nil;
loadable_categories_used = 0;
loadable_categories_allocated = 0;
}
if (PrintLoading) {
if (loadable_categories_used != 0) {
_objc_inform("LOAD: %d categories still waiting for +load\n",
loadable_categories_used);
}
}
return new_categories_added;
}
- 遍历loadable_categories,逐个调用cls中的+load方法
总结:
- 分类的加载顺序:父类->子类->分类
- 加载分两步:先准备加载,把对应的类、分类存储到数组中;再遍历数组,逐个调用。
- +load与普通方法不同,不会存在分类覆盖类的方法,每个分类中的+load也是单独存在的。
网友评论