iOS - load 方法探索

2018-05-02  本文已影响0人  felix6

[toc]

参考

load

initialize

http://www.jianshu.com/p/a358a397a4ce

http://blog.csdn.net/ShengQiangLiu/article/details/50866228

code

// NSObject 有实现该方法
- (void)load;

objc4源码解读

// objc-os.mm
_objc_init();

// objc-runtime-new.mm
load_images();
        // 准备(查找所有被实现的load方法)
        prepare_load_methods(); // Discover load methods
                /// 类 ★
                // 按(编译)顺序加载 classlist 数组中的类, 这个顺序就是 BuildPhases 中 CompileSources 的顺序
                classref_t const *classlist = _getObjc2NonlazyClassList(mhdr, &count);
                schedule_class_load(remapClass(classlist[i])); // for循环
                        // ★★ 递归调用, 传入super, 所以父类早于子类添加到数组中, 保证父类早于子类load 
                        schedule_class_load(cls->superclass);
                        // ★★ 将cls添加到 loadable_classes 数组的最后面, call_class_loads()是从前往后遍历, 所以后添加的后加载; 
                        add_class_to_loadable_list(); 
                                method = cls->getLoadMethod(); // 获取 load 的IMP
                                if (!method) return; // ★★ 如果类没有实现 +load, 则不加入数组, 后面也不会去调用 
                                loadable_classes[loadable_classes_used].cls = cls;
                                loadable_classes[loadable_classes_used].method = method;
                /// 分类 ★
                // 按(编译)顺序加载 categorylist 数组中的分类
                category_t * const *categorylist = _getObjc2NonlazyCategoryList(mhdr, &count);
                // for循环, 将 cat 添加到 loadable_categories
                // 注意, 分类这里没有递归调用, 不用管 super
                add_category_to_loadable_list(); 
                        method = _category_getLoadMethod(cat);
                        if (!method) return;
                        loadable_categories[loadable_categories_used].cat = cat;
                        loadable_categories[loadable_categories_used].method = method;
        
        // 加载
        call_load_methods(); // objc-loadmethod.mm
                // 先调用所有类的load
                call_class_loads();
                        // 从上面prepare好的 loadable_classes 数组中取出所有类
                        struct loadable_class *classes = loadable_classes;
                        // for循环该数组, 取到类的load方法的内存地址, 赋值给函数指针load_method
                        load_method_t load_method = (load_method_t)classes[i].method;
                        // 使用函数指针, 直接调用每一个类的load方法
                        (*load_method)(cls, @selector(load));
                // 再调用所有分类的load
                call_category_loads();
                        load_method_t load_method = (load_method_t)cats[i].method;
                        (*load_method)(cls, @selector(load));
                        
结论★★:

调用时机:

+ load方法会在runtime加载类、分类时调用 [TBC ??? load 是 runtime 调用的吗]

程序一启动, 在main()函数执行之前, 当类或分类被加载到内存时被调用。

换句话说, 这个load方法在 didFinishLaunchingWithOptions 之前就被调用了;

《Apple Document》
Invoked whenever a class or category is added to the Objective-C runtime; implement this method to perform class-specific behavior upon loading.

调用次数:

每个类、分类的+ load,在程序运行过程中, 默认会且只会执行一次

调用必然性:

必然调用, 不管程序运行过程中有没有用到这个类, 都会调用load方法 (如果有实现)

调用顺序:

image

同一继承体系下, 先加载父类, 再加载子类, 然后再加载子类的分类(按编译顺序, 先编译先调用);
不同的类之间的加载顺序: 是不确定的 按照编译先后顺序调用(先编译, 先调用)。

《Apple Document》
A class’s +load method is called after all of its superclasses’ +load methods.
A category +load method is called after the class’s own +load method.

见【objc4源码解读 - 结论】

父类

父类先于子类加载, 子类不要手动调用 [super load] , 否则父类的load会执行多次。

load 不遵循继承规则, 不管子类有没有写load方法, 都不会去查找调用父类的load

分类

与其他方法不同, 每个类的load都是独立的, 不存在继承、重写, 在Category中重写load函数不会替换原始类中的load, 原始类和Category中的load函数都会被执行, 原始类的load会先被执行, 再执行Category中的load函数。

当有多个 Category 都实现了load函数, 这几个load函数都会执行, 按编译顺序, 先编译先调用。

调用方式:

系统自动调用, 不要手动调用 (但实际也能调用)

安全性

线程安全 内部加锁 线程阻塞

在load方法中使用其他类是不安全的, 因为会调用其他类的load方法, 而如果关系复杂的话, 就无法判断出各个类的载入顺序, 类只有初始化完成后, 类实例才能进行正常使用

尽可能的精简load方法, 因为整个应用程序在执行load方法时会阻塞, 即, 程序会阻塞直到所有类的load方法执行完毕, 才会继续

应用场景

一般的应用场景是在该方法中实现方法交换(Method Swizzling)

面试题

Category中有load方法吗?load方法是什么时候调用的?

有load方法

load方法在runtime加载类、分类的时候调用 【TBC】

load 方法能继承吗?★★
load、initialize的区别?
load、initialize 的调用顺序?
load、initialize 在category中的调用的顺序?
load、initialize 出现继承时他们之间的调用过程?
系统是怎么调用 load 方法的?

不是通过消息机制, 而是直接通过函数指针调用

上一篇 下一篇

猜你喜欢

热点阅读