问题
Person
类中有一个run
方法,
Person
的Category1
中也有一个run
方法,
Person
的Category2
中也有一个run
方法,
调用[Person run]
时响应的是哪个方法?
答案:
根据两个分类的编译顺序,调用的是后编译的Category
中的run
方法。
原因:
runtime
将Person
的元类对象中的类方法和Category
中的类方法合并了,逆序<编译顺序>获取分类指针,并且将Category
中的类方法,放在了方法列表的前面。所以调用run
方法的时候,优先找到的是Category
中的类方法。
方法列表顺序为:
【Category2】【Category1】【Person】
接着上面的问题继续:
Person
中实现+(void)load
方法,
Person
的Category1
中实现+(void)load
方法,
Person
的Category2
中实现+(void)load
方法
运行,调用谁的load
方法?
答案:
都调用了
load -- Person
load -- Person (Extension1)
load -- Person (Extension2)
感觉和上面的问题对不上了。方法名一样的话不应该只调用一个吗?
原因分析:
下载objc源码看一下
源码地址:https://opensource.apple.com/tarballs/objc4/
顺着下面的方法直接找到最终目的地
void _objc_init(void)
load_images
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();
}
// 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;
}
第一步,调用所有的类的load
方法
// 1. Repeatedly call class +loads until there aren't any more
while (loadable_classes_used > 0) {
call_class_loads();
}
call_class_loads();
中,
循环遍历所有的class
,
然后直接找到load
方法,
直接进行调用<(*load_method)(cls, SEL_load);
>
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);
}
第二步,调用所有分类中的load方法
call_category_loads();
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;
}
}
所以+ (void)load;
方法class
中和Category
中的都会在runtime的时候调用
原因
调用顺序
先调用class中的load方法
再按照编译顺序调用Category中的load方法
网友评论