18期_iOS_分类的加载分析
2023-08-20 本文已影响0人
萧修
在类的加载中,其中函数map_iamges为主要流程,最后执行read_images,此流程最后为分类的加载,看代码
void _read_images(header_info **hList, uint32_t hCount, int totalClasses, int unoptimizedTotalClasses)
{
bool hasClassProperties = hi->info()->hasCategoryClassProperties();
size_t count;
auto processCatlist = [&](category_t * const *catlist) {
for (unsigned i = 0; i < count; i++) {
category_t *cat = catlist[i];
Class cls = remapClass(cat->cls);
locstamped_category_t lc{cat, hi};
}
}
}
由上面的代码可知,从macho中的objc_catlist读取的分类,我们来看category_t
的结构。详细结构可查看分类的本质
懒加载和非懒加载
从以往经验中,实现+load
方法的类,会提前加载。,此方法何时执行,接下来分析libobjc从dyld接受的`load_imags开始分析
_dyld_objc_notify_register(&map_images, load_images, unmap_image);
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);
//准备load方法
prepare_load_methods((const headerType *)mh);
}
// Call +load methods (without runtimeLock - re-entrant)
//调用load方法
call_load_methods();
}
//prepare_load_methods加载
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]));
}
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);
}
}
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
schedule_class_load(cls->getSuperclass());
add_class_to_loadable_list(cls);
cls->setInfo(RW_LOADED);
}
由上面三段代码:先父类后子类的,将+load
方法添加到对应的loadable表中。
是否是懒加载,取决于由+load
类的懒加载和非懒加载与分类的懒加载和非懒加载,同友四种情况
- 分类是懒加载的,编译时就会被加入到ro【分类未实现load】
- 分类是非懒加载的,根据类是否是懒加载决定加载流程。
类为懒加载:会在分类的+load之前调用前加载。(因为分类的方法要附加到类中,realizeClassWithoutSwift - methodizeClass
)
类为非懒加载:类启动的时候就加载了,在read_images
附加分类信息 - 类懒加载,根据分类是懒加载,分类懒加载,第一次使用加载,非懒加载,分类的+load之前被加载
类拓展和分类
类扩展是类编译时就被当做类的一部分,而分类是运行时才添加进去,而编译后的ro已经确定,属性要加入ro不被允许,rw没有成员变量字段,系统只声明set和getter
initialize
子类没有实现,父类实现,初始化子类父类会多次调用。
系统较早执行的方法