+load and +initialize 区别
1:+load 在对象载入内存的时候调用并且是通过函数地址 直接调用
- 和对象的编译顺序有关
- 先调用父类、在调用子类
2:+initialize 在对象第一次接受到消息 的时候调用,使用 objcMsgSend()
- 当子类没有实现方法的时候,会多次调用父类的方法
- 先调用父类、在调用子类
+load源码分析
1、入口文件查找 objc-os.mm
1:void _objc_init(void)
objc-runtime-new.mm
2、objc-runtime-new.mm
2.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;
recursive_mutex_locker_t lock(loadMethodLock);
// Discover load methods
{
mutex_locker_t lock2(runtimeLock);
prepare_load_methods((const headerType *)mh);
}
// Call +load methods (without runtimeLock - re-entrant)
///根据prepare_load_methods的查找顺序
//会优先调用父类的load,然后子类 最后category
call_load_methods();
}
2.2 准备load方法
void prepare_load_methods(const headerType *mhdr)
{
size_t count, i;
runtimeLock.assertLocked();
///取出对象列表,和编译顺序有关
classref_t const *classlist =
_getObjc2NonlazyClassList(mhdr, &count);
for (i = 0; i < count; i++) {
schedule_class_load(remapClass(classlist[i]));
}
///加载分类load
category_t * const *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
if (cls->isSwiftStable()) {
_objc_fatal("Swift class extensions and categories on Swift "
"classes are not allowed to have +load methods");
}
realizeClassWithoutSwift(cls, nil);
ASSERT(cls->ISA()->isRealized());
add_category_to_loadable_list(cat);
}
}
2.3 class 查找load方法
static void schedule_class_load(Class cls)
{
if (!cls) return;
ASSERT(cls->isRealized()); // _read_images should realize
if (cls->data()->flags & RW_LOADED) return;
// Ensure superclass-first ordering
///递归寻找父类的load方法 so 在调用load方法的时候 会先查找到父类的方法,并添加到add_class_to_loadable_list中
schedule_class_load(cls->superclass);
add_class_to_loadable_list(cls);
cls->setInfo(RW_LOADED);
}
2.4 查找分类的load方法,根据编译顺序直接添加到列表中
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++;
}
3、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
///先调用class的load方法
while (loadable_classes_used > 0) {
call_class_loads();
}
// 2. Call category +loads ONCE
///调用扩展方法的load方法
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;
}
3.1、class load方法调用
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方法
(*load_method)(cls, @selector(load));
}
// Destroy the detached list.
if (classes) free(classes);
}
3.2、扩展load方法调用
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, @selector(load));
cats[i].cat = nil;
}
}
return new_categories_added;
}
+initialize源码阅读
方法查看顺序 -objc-runtime-new.mm
///查找对象实例化方法
- Method class_getInstanceMethod(Class cls, SEL sel)
- lookUpImpOrForward(nil, sel, cls, LOOKUP_RESOLVER);///查找方法实现
- static Class initializeAndLeaveLocked(Class cls, id obj, mutex_t& lock)
- static Class initializeAndMaybeRelock(Class cls, id inst,mutex_t& lock, bool leaveLocked)
- void initializeNonMetaClass(Class cls)///初始化没有初始化的元对象
void initializeNonMetaClass(Class cls)
{
ASSERT(!cls->isMetaClass());
Class supercls;
bool reallyInitialize = NO;
// Make sure super is done initializing BEFORE beginning to initialize cls.
// See note about deadlock above.
///优先初始化父类
supercls = cls->superclass;
///如果父类存在并且父类未初始化,就初始化父类
if (supercls && !supercls->isInitialized()) {
initializeNonMetaClass(supercls);
}
// Try to atomically set CLS_INITIALIZING.
SmallVector<_objc_willInitializeClassCallback, 1> localWillInitializeFuncs;
{
monitor_locker_t lock(classInitLock);
///如果本身未初始化并且没有 调用过isInitializing方法
if (!cls->isInitialized() && !cls->isInitializing()) {
cls->setInitializing();
reallyInitialize = YES;
// Grab a copy of the will-initialize funcs with the lock held.
localWillInitializeFuncs.initFrom(willInitializeFuncs);
}
}
///initialize方法调用
/*
///消息发送
void callInitialize(Class cls)
{
((void(*)(Class, SEL))objc_msgSend)(cls, @selector(initialize));
asm("");
}
*/
callInitialize(cls);
}