美文网首页
+load与+initialize

+load与+initialize

作者: oneday527 | 来源:发表于2018-02-26 14:00 被阅读0次

    一、initialize

    1、在程序中向一个类或者它的子类第一次发消息的之前,runtime会向该类发送initialize消息。
    2、父类在其子类之前接收initialize消息。如果superclass之前没有收到过initialize消息,会首先调用super class的initialize,然后才当前class的initialize。

    3、如果子类没有实现initialize方法,或者子类显式调用[super initialize],superclass的实现会被多次调用。
    4、runtime以线程安全的方式将initialize消息发送给类。也就是说,initialize由第一个线程运行,以向类发送消息,并且任何试图向该类发送消息的线程都将阻塞,直到initialize完成。
    5、如果您希望保护自己不被多次运行,您可以按照以下的方式来构造您的方法:

    + (void)initialize {
      if (self == [ClassName self]) {
        // ... do the initialization ...
      }
    }
    

    6、因为initialize是以阻塞的方式被调用,所以在initialize方法中不适宜做过于繁重的初始化工作。特别注意,如果加锁的代码在其他类的initialize方法中调用有可能会导致死锁。因此,不应该依赖于initialize来进行复杂的初始化,而应该完成一些简单的本地初始化。
    7、initialize在每个类中只调用一次,如果在category中重写了initialize方法,会覆盖当前类的initialize方法。如果您想为类和类别执行独立的初始化,您应该实现+load方法。

    二、load

    在类或类别添加到runtime时调用;在这个方法中可以执行一些特定的行为。比如初始化一个全局的表,并将类注册到其中。

    #不像initialize,不存在重复调用的情况。
    + (void)load;
    

    初始化过程:
    所有链接的framework的initializer

    所有+load方法

    本程序的所有C++static initializer 和C/C++ attribute(constructor)方法

    所有链接本程序的framework的initializer
    【注】
    当所有super class的load方法调用完成,才执行当前类的load方法
    当前class的load方法调用完成,才执行当前category的load方法

    三、示例

    1、

    #本文中用到的示例,大家可以分别注释子类或是父类的initialize或是load方法,运行看看有什么不同#
    
    #Father:父类
    #import <Foundation/Foundation.h>
    @interface Father : NSObject
    @end
    
    #import "Father.h"
    @implementation Father
    + (void)initialize{
        NSLog(@"%s",__func__);
    }
    
    + (void)load{
        NSLog(@"%s",__func__);
    }
    @end
    
    #Son1:继承Father的子类
    #import "Father.h"
    @interface Son1 : Father
    @end
    
    #import "Son1.h"
    @implementation Son1
    + (void)initialize{
        NSLog(@"%s",__func__);
    }
    + (void)load{
        NSLog(@"%s",__func__);
    }
    @end
    
    #Son2:继承Father的子类
    #import "Father.h"
    @interface Son2 : Father
    @end
    
    #import "Son2.h"
    @implementation Son2
    + (void)initialize{
        NSLog(@"%s",__func__);
    }
    
    + (void)load{
        NSLog(@"%s",__func__);
    }
    @end
    
    #Son1+Load: Son1的分类
    #import "Son1.h"
    @interface Son1 (Load)
    @end
    
    #import "Son1+Load.h"
    @implementation Son1 (Load)
    + (void)initialize{
        NSLog(@"%s",__func__);
    }
    + (void)load{
        NSLog(@"%s",__func__);
    }
    @end
    

    我们只是创建了几个类,什么都不做,运行一下

    2018-02-26 12:54:23.054726+0800 runtimeDemo[31256:5838555] +[Father load]
    2018-02-26 12:54:23.055196+0800 runtimeDemo[31256:5838555] +[Son1 load]
    2018-02-26 12:54:23.055801+0800 runtimeDemo[31256:5838555] +[Son2 load]
    2018-02-26 12:54:23.055879+0800 runtimeDemo[31256:5838555] +[Son1(Load) load]
    

    2、若子类没有实现initialize

    #import "Son2.h"
    @implementation Son2
    //+ (void)initialize{
    //    NSLog(@"%s",__func__);
    //}
    + (void)load{
        NSLog(@"%s",__func__);
    }
    @end
    
    #import "ViewController.h"
    #import "Son2.h"
    @interface ViewController ()
    
    @end
    @implementation ViewController
    - (void)viewDidLoad {
        [super viewDidLoad];
        // Do any additional setup after loading the view, typically from a nib.
        [Son2 new];
    }
    

    控制台

    2018-02-26 13:30:13.318882+0800 runtimeDemo[31794:5867109] +[Father load]
    2018-02-26 13:30:13.319541+0800 runtimeDemo[31794:5867109] +[Son1 load]
    2018-02-26 13:30:13.319988+0800 runtimeDemo[31794:5867109] +[Son2 load]
    2018-02-26 13:30:13.320241+0800 runtimeDemo[31794:5867109] +[Son1(Load) load]
    
    2018-02-26 13:30:13.992162+0800 runtimeDemo[31794:5867109] +[Father initialize]
    2018-02-26 13:30:13.992247+0800 runtimeDemo[31794:5867109] +[Father initialize]
    

    3、+load 执行时机

    @implementation ViewController
    - (void)viewDidLoad {
        [super viewDidLoad];
        [Father new];
        [Son1 new];
        [Son2 new];
    }
    @end
    

    控制台

    2018-02-26 13:37:48.911794+0800 runtimeDemo[32019:5876718] +[Father load]
    2018-02-26 13:37:48.912212+0800 runtimeDemo[32019:5876718] +[Son1 load]
    2018-02-26 13:37:48.912451+0800 runtimeDemo[32019:5876718] +[Son2 load]
    2018-02-26 13:37:48.912835+0800 runtimeDemo[32019:5876718] +[Son1(Load) load]
    2018-02-26 13:37:48.912950+0800 runtimeDemo[32019:5876718] main
    2018-02-26 13:37:49.892705+0800 runtimeDemo[32019:5876718] -[AppDelegate application:didFinishLaunchingWithOptions:]
    2018-02-26 13:37:49.894483+0800 runtimeDemo[32019:5876718] +[Father initialize]
    2018-02-26 13:37:49.894563+0800 runtimeDemo[32019:5876718] +[Son1(Load) initialize]
    2018-02-26 13:37:49.894652+0800 runtimeDemo[32019:5876718] +[Son2 initialize]
    

    【总结】
    1、+load 类加载到runtime就会调用,按照父类,子类,分类的顺序进行加载。
    2、若有多个子类,加载顺序依照building setting中compile sources 中的子类顺序进行加载
    3、若父类子类均有分类,加载顺序依照building setting中compile sources 中的分类先后顺序进行加载。

    多个子类&多个分类
    compile sourcese

    加载顺序

    2018-02-26 13:44:34.522342+0800 runtimeDemo[32225:5885402] +[Father load]
    2018-02-26 13:44:34.523200+0800 runtimeDemo[32225:5885402] +[Son2 load]
    2018-02-26 13:44:34.523312+0800 runtimeDemo[32225:5885402] +[Son1 load]
    2018-02-26 13:44:34.523576+0800 runtimeDemo[32225:5885402] +[Son2(Load) load]
    2018-02-26 13:44:34.523720+0800 runtimeDemo[32225:5885402] +[Son1(Load) load]
    2018-02-26 13:44:34.523912+0800 runtimeDemo[32225:5885402] +[Father(Load) load]
    2018-02-26 13:44:34.524117+0800 runtimeDemo[32225:5885402] main
    2018-02-26 13:44:35.516505+0800 runtimeDemo[32225:5885402] -[AppDelegate application:didFinishLaunchingWithOptions:]
    

    4、initialize只有在用到类的时候才会被调用。
    5、父类initialize可能会被调用多次。

    四、应用场景

    1、+load方法中完成swizzing method。
    2、统跳协议模式的模块化工程,每个类在+load方法中注册当前类可以相应的链接。
    3、等等

    以上,掌握这两个方法在程序加载的时候做一些初始化的工作。
    如果有不准确的地方,欢迎批评指正。

    相关文章

      网友评论

          本文标题:+load与+initialize

          本文链接:https://www.haomeiwen.com/subject/lphiixtx.html