+load && +initialize 使用

+load && +initialize 作用、加载次序(Category)

+load

+load 定义

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

通过关键字可以看出

  • 作用:“perform class-specific behavior upon loading” 在类加载前执行类的一些行为
  • 条件:“whenever a class or category is added” 在类中或者分类中添加(被加载时)就会被调用,猜测:这里如果为了优化,应该在编译期间,就把实现+load的类通过放在某个列表中,然后依次执行,或者在类中有个标记。为什么不是Cocoa中比较流行的注册机制,因为被加载时,运行时系统是“脆弱”的,只加载了基本的框架(Foundation),详见下文。
  • 方式:“runtime” 也是通过运行时进行加载。看下面的“message”

The load message is sent to classes and categories that are both dynamically loaded and statically linked, but only if the newly loaded class or category implements a method that can respond.

当类或者分类可以响应load方法时,才发送load消息,但此时该类已经动态加载和静态链接的。

关于+load加载时机

  • 程序初始化步骤:

    The order of initialization is as follows:
    All initializers in any framework you link to.
    All +load methods in your image.
    All C++ static initializers and C/C++ attribute(constructor) > functions in your image.
    All initializers in frameworks that link to you.

但是这个2 和 3 的顺序是跟WWDC 2016 相反的
但是总体都是说初始化FrameWork → +load → main()函数 → 类的 initialize 方法 → 根据生命周期调用类的其他方法.

其中image的意思是:资源(WWDC 2016)

File Types:

Executable—Main binary for application
Dylib—Dynamic library (aka DSO or DLL)
Bundle—Dylib that cannot be linked, only dlopen(), e.g. plug-ins
Image—An executable, dylib, or bundle

+load的次序

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.

  • 对于子类和父类,类和分类的调用顺序已经写明:

1、先调用超类的+load ,在调用子类的+load;

2、先调用完所有类的+load,在调用分类的+load。

  • 那么其他文件的+load调用顺序是怎么样的?

[图片]

与 Build Phases 中的 Compile Sources 顺序一致。
同一个类的分类调用顺序是怎么样的?
与 Build Phases 中的 Compile Sources 顺序一致。

  • 概括:

1、先调用超类的+load ,在调用子类的+load
2、先调用完所有类的+load,在调用分类的+load,即分类的+load总是会放在最后类的后面
3、按照Compile Sources 顺序执行

+load的注意事项:

In a custom implementation of load you can therefore safely message other unrelated classes from the same image, but any load methods implemented by those classes may not have run yet.

  • 在+load方法中,我们可以安全的给不相关的类发消息,但是+load方法中不应该调用他们

Custom implementations of the load method for Swift classes bridged to Objective-C are not called automatically.

  • swift 桥接到OC的混合编程中,swift的自定义的+load实现 不会自动调用。

  • 因为+load在启动前就加载运行,过度的使用会影响首页加载时间

+initialize

  • 时机:类第一次被调用时

    Initializes the class before it receives its first message.

  • 执行顺序
    父类 优先 子类调用 initialize

该类的方法在其他类+load时期被调用,那么initialize调用,而后该类的+load在调用,因此+initialize可以比+load先调用

category 的覆写效应对 load 方法无效,但对 initialize 方法有效。且按 Complile Sources 的顺序,后面的会覆盖前面的。

  • initialize是线程安全的,其他线程需要等待第一个执行完执行完之后在进行执行。可以理解为@synchronized(self),因此注意,在initialize中只进行必要初始化操作

  • 父类的initialize会被调用多次,因此注意下副作用。因为存在子类没实现initialize或者子类主动调用initialize的情况

如果想避免,可以

1
2
3
4
5
+ (void)initialize {
if (self == [ClassName self]) {
// ... do the initialization ...
}
}

initialize is invoked only once per class. If you want to perform independent initialization for the class and for categories of the class, you should implement load methods.

最后

  • +load 和 + initialize 只被调用一次,是指启动时runtime机制而言,他们也可以被当做普通的类方法被调用,但是一般别这么使用。

  • 如果子类没有实现+load和+initialize, 会调用父类的+load和父类的initialize方法。

  • category 不会覆盖类的+load,但是会覆盖类的+initialize