+load init ios

2016-08-06 14:30:31 cugwuhan2014 阅读数 215

一、+ initialize 方法和+load 调用时机

  • 首先说一下 + initialize 方法:苹果官方对这个方法有这样的一段描述:这个方法会在 第一次初始化这个类之前 被调用,我们用它来初始化静态变量。
    • load 方法会在加载类的时候就被调用,也就是 ios 应用启动的时候,就会加载所有的类,就会调用每个类的 + load 方法。
  • 之后我们结合代码来探究一下 + initialize 与 + load 两个方法的调用时机,首先是 + load
    #pragram ---main函数中的代码---
    #import <UIKit/UIKit.h>
    #import "AppDelegate.h"
    int main(int argc, char * argv[]) {
      NSLog(@"%s",__func__);
      @autoreleasepool {
          return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
      }
    }
    #pragram ---基于NSObject的Person类---
    #import "Person.h"
    @implementation Person
    + (void)load{
      NSLog(@"%s",__func__);
    }
    + (void)initialize{
      [super initialize];
      NSLog(@"%s %@",__func__,[self class]);
    }
    - (instancetype)init{
      if (self = [super init]) {
          NSLog(@"%s",__func__);
      }
      return self;
    }
    @end
    #pragram ---基于Person的Son类---
    #import "Girl.h"
    @implementation Girl
    + (void)load{
      NSLog(@"%s ",__func__);
    }
    + (void)initialize{
      [super initialize];
      NSLog(@"%s ",__func__);
    }
    - (instancetype)init{
      if (self = [super init]) {
          NSLog(@"%s",__func__);
      }
      return self;
    }
    @end
    运行程序,我们看一下输出日志:
    2015-10-27 15:21:07.545 initialize[11637:334237] +[Person load]
    2015-10-27 15:21:07.546 initialize[11637:334237] +[Girl load] 
    2015-10-27 15:21:07.546 initialize[11637:334237] main
    这说明在我并没有对类做任何操作的情况下,+load 方法会被默认执行,并且是在 main 函数之前执行的。
  • 接下来我们来查看一下 + initialize 方法,先在 ViewController 中创建 Person 和 Girl 对象:
    #import "ViewController.h"
    #import "Person.h"
    #import "Son.h"
    #import "Girl.h"
    @interface ViewController ()
    @end
    @implementation ViewController
    - (void)viewDidLoad {
      [super viewDidLoad];
      Person * a = [Person new];
      Person * b = [Person new];
      Girl *c = [Girl new];
      Girl *d = [Girl new];
    }
    @end
    下面我们来看一下输出日志:
    2015-10-27 15:33:56.195 initialize[11711:342410] +[Person load]
    2015-10-27 15:33:56.196 initialize[11711:342410] +[Girl load] 
    2015-10-27 15:33:56.197 initialize[11711:342410] main
    2015-10-27 15:33:56.259 initialize[11711:342410] +[Person initialize] Person
    2015-10-27 15:33:56.259 initialize[11711:342410] -[Person init]
    2015-10-27 15:33:56.259 initialize[11711:342410] -[Person init]
    2015-10-27 15:33:56.259 initialize[11711:342410] +[Girl initialize] 
    2015-10-27 15:33:56.260 initialize[11711:342410] -[Girl init]
    2015-10-27 15:33:56.260 initialize[11711:342410] -[Girl init]
    通过这个实验我们可以确定两点:
    • + initialize 方法类似一个懒加载,如果没有使用这个类,那么系统默认不会去调用这个方法,且默认只加载一次;
    • + initialize 的调用发生在 +init 方法之前。
  • 接下来再探究一下 + initialize 在父类与子类之间的关系,创建一个继承自 Person 类的 Son类:
    #pragram ---ViewController 中的代码---
    #import "ViewController.h"
    #import "Person.h"
    #import "Son.h"
    #import "Girl.h"
    @interface ViewController ()
    @end
    @implementation ViewController
    - (void)viewDidLoad {
      [super viewDidLoad];
      Person * a = [Person new];
      Person * b = [Person new];
      Son*z = [Son new];
    }
    @end
    看一下输出日志:
    2015-10-27 15:44:55.762 initialize[12024:351576] +[Person load]
    2015-10-27 15:44:55.764 initialize[12024:351576] +[Son load]
    2015-10-27 15:44:55.764 initialize[12024:351576] +[Girl load] 
    2015-10-27 15:44:55.764 initialize[12024:351576] main
    2015-10-27 15:44:55.825 initialize[12024:351576] +[Person initialize] Person
    2015-10-27 15:44:55.825 initialize[12024:351576] -[Person init]
    2015-10-27 15:44:55.825 initialize[12024:351576] -[Person init]
    2015-10-27 15:44:55.826 initialize[12024:351576] +[Person initialize] Son
    2015-10-27 15:44:55.826 initialize[12024:351576] -[Person init]
    我们会发现 Person 类的 + initialize 方法又被调用了,但是查看一下是子类 Son 调用的,也就是创建子类的时候,子类会去调用父类的 + initialize 方法。

二、总结

  • 如果你实现了 + load 方法,那么当类被加载时它会自动被调用。这个调用非常早。如果你实现了一个应用或框架的 + load,并且你的应用链接到这个框架上了,那么 + load 会在 main() 函数之前被调用。如果你在一个可加载的 bundle 中实现了 + load,那么它会在 bundle 加载的过程中被调用。
  • + initialize 方法的调用看起来会更合理,通常在它里面写代码比在 + load 里写更好。+ initialize 很有趣,因为它是懒调用的,也有可能完全不被调用。类第一次被加载时,
  • + initialize 不会被调用。类接收消息时,运行时会先检查 + initialize 有没有被调用过。如果没有,会在消息被处理前调用。

 

文/Mitchell(简书作者)
原文链接:http://www.jianshu.com/p/9368ce9bb8f9
著作权归作者所有,转载请联系作者获得授权,并标注“简书作者”。

2019-07-15 17:59:19 gjx121233 阅读数 95
对于 iOS 开发者而言,+load()+initialize()-init() 方法应该并不陌生,但是,对于这些方法的调用逻辑和顺序,可能会偶有疑惑,本文通过 demo 的方式,来探究一下这几个方法

+ load()

+load() 方法是当类或分类被添加到 Objective-C runtime 时被调用的,实现这个方法可以让我们在类加载的时候执行一些类相关的行为,子类的 +load 方法会在它的所有父类的 +load() 方法之后执行,而分类的 +load() 方法会在它的主类的 +load() 方法之后执行。但是不同的类之间的 +load()方法的调用顺序是不确定的
image.png
我们先创建一个 TestClass 类,然后在创建一个继承自该类的子类 TestClassSubClass,和两个 TestClass 的分类 TestClass+ZTestClass+Y,分别在这几个类中实现 +load() 方法,并打印输出,然后在 main() 中也写一个输出语句,运行程序,我们来看一下输出

int main(int argc, char * argv[]) {
    @autoreleasepool {
        
        NSLog(@"  %s", __func__);
        
        return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
    }
}

image.png

如我们所看到的,+load() 的调用是在 main() 函数之前,并且在整个 APP 运行过程中只会被调用一次,对 +load() 方法进行调用,是直接使用函数内存地址的方式 (load_method)(cls, SEL_load); 而不是使用发送消息 objc_msgSend 的方式,父类 TestClass+load()方法最先被调用,而后是子类和分类,对于多个分类的 +load() 的调用顺序的先后,取决于编译顺序,测试一下,我们在 Bulid Phases->Compile Sources 调整分类的编译顺序
image.png

image.png
会看到 TestClass+Z+load() 方法先于 TestClass+Y 被调用

结论:
  • +load() 方法的调用是在 main() 函数之前,并且不需要主动调用,程序启动会把所有的文件加载,文件如果重写了 +load() 方法,主类、子类、分类都会加载调用 +load() 方法;
  • 主类与分类的加载顺序是: 主类优先于分类加载,无关编译顺序;
  • 分类间的加载顺序取决于编译的顺序: 先编译先加载,后编译则后加载;
  • 优先顺序: (父类 > 子类 > 分类)
  • 因为 +load() 是在 main() 函数之前调用,所以在这个方法里面不要作耗时操作或者阻塞的操作,会影响启动速度;
  • 不要做对象的初始化操作,因为在 main() 函数之前自动调用,+load() 方法调用的时候使用者根本就不能确定自己要使用的对象是否已经加载进来了,所以千万不能在这里初始化对象;
  • 可以根据业务需求,在 +load() 方法中进行 Method Swizzle 操作,交换方法

+ initialize()

+initialize() 方法是在类或它的子类收到第一条消息之前被调用的,这里所指的消息包括实例方法和类方法的调用,也就是说 +initialize() 方法是以懒加载的方式被调用的,如果程序一直没有给某个类或它的子类发送消息,那么这个类的 +initialize() 方法是永远不会被调用的,关于调用,我们同样用代码进行测试

  • TestClass 实现 + initialize() 方法,子类和分类中不实现,分别如下调用
      TestClass *class1 = [[TestClass alloc] init];
      TestClass *class2 = [[TestClass alloc] init];
    
//    TestClassSubClass *subClass1 = [[TestClassSubClass alloc] init];
//    TestClassSubClass *subClass2 = [[TestClassSubClass alloc] init];
//    TestClassSubClass *subClass3 = [[TestClassSubClass alloc] init];
//    TestClassSubClass *subClass4 = [[TestClassSubClass alloc] init];
//    TestClassSubClass *subClass5 = [[TestClassSubClass alloc] init];

image.png

    TestClass *class1 = [[TestClass alloc] init];
    TestClass *class2 = [[TestClass alloc] init];
    
    TestClassSubClass *subClass1 = [[TestClassSubClass alloc] init];
    TestClassSubClass *subClass2 = [[TestClassSubClass alloc] init];
    TestClassSubClass *subClass3 = [[TestClassSubClass alloc] init];
    TestClassSubClass *subClass4 = [[TestClassSubClass alloc] init];
    TestClassSubClass *subClass5 = [[TestClassSubClass alloc] init];

image.png


//    TestClass *class1 = [[TestClass alloc] init];
//    TestClass *class2 = [[TestClass alloc] init];
    
    TestClassSubClass *subClass1 = [[TestClassSubClass alloc] init];
    TestClassSubClass *subClass2 = [[TestClassSubClass alloc] init];
    TestClassSubClass *subClass3 = [[TestClassSubClass alloc] init];
    TestClassSubClass *subClass4 = [[TestClassSubClass alloc] init];
    TestClassSubClass *subClass5 = [[TestClassSubClass alloc] init];

image.png

会发现,不管我们创建 TestClass 几个对象,[TestClass initialize]只被调用一次,而如果创建了 TestClassSubClass 对象,无论是否创建 TestClass 对象,[TestClass initialize] 都会调用两次,可见当子类未实现 +initialize() 方法,会调用父类 +initialize() 方法。

  • TestClass 和子类中分别实现 + initialize 方法
    TestClass *class1 = [[TestClass alloc] init];
    TestClass *class2 = [[TestClass alloc] init];
    
    TestClassSubClass *subClass1 = [[TestClassSubClass alloc] init];
    TestClassSubClass *subClass2 = [[TestClassSubClass alloc] init];
    TestClassSubClass *subClass3 = [[TestClassSubClass alloc] init];
    TestClassSubClass *subClass4 = [[TestClassSubClass alloc] init];
    TestClassSubClass *subClass5 = [[TestClassSubClass alloc] init];

image.png

//    TestClass *class1 = [[TestClass alloc] init];
//    TestClass *class2 = [[TestClass alloc] init];
    
    TestClassSubClass *subClass1 = [[TestClassSubClass alloc] init];
    TestClassSubClass *subClass2 = [[TestClassSubClass alloc] init];
    TestClassSubClass *subClass3 = [[TestClassSubClass alloc] init];
    TestClassSubClass *subClass4 = [[TestClassSubClass alloc] init];
    TestClassSubClass *subClass5 = [[TestClassSubClass alloc] init];

image.png
可见,无论子类中是否实现了 + initialize() 方法,初始化都会至少去调用一次父类的 + initialize() 方法,而如果自身实现了 + initialize() 方法,那么继续调用自己的 + initialize() 方法,如果未实现,则去调用父类的 + initialize()方法

  • TestClass 和子类、分类中分别实现 + initialize() 方法
    TestClass *class1 = [[TestClass alloc] init];
    TestClass *class2 = [[TestClass alloc] init];
    
    TestClassSubClass *subClass1 = [[TestClassSubClass alloc] init];
    TestClassSubClass *subClass2 = [[TestClassSubClass alloc] init];
    TestClassSubClass *subClass3 = [[TestClassSubClass alloc] init];
    TestClassSubClass *subClass4 = [[TestClassSubClass alloc] init];
    TestClassSubClass *subClass5 = [[TestClassSubClass alloc] init];
//    TestClass *class1 = [[TestClass alloc] init];
//    TestClass *class2 = [[TestClass alloc] init];
    
    TestClassSubClass *subClass1 = [[TestClassSubClass alloc] init];
    TestClassSubClass *subClass2 = [[TestClassSubClass alloc] init];
    TestClassSubClass *subClass3 = [[TestClassSubClass alloc] init];
    TestClassSubClass *subClass4 = [[TestClassSubClass alloc] init];
    TestClassSubClass *subClass5 = [[TestClassSubClass alloc] init];

image.png
根据输出我们看到,之前的调用父类的 + initialize() 方法,变成了调用 TestClass+Y+ initialize() 方法,这是因为最后被编译的 TestClass+Y 中的 + initialize() 方法覆盖了主类的 + initialize() 方法

结论:
  • 父类的 + initialize() 方法会比子类先执行;
  • 当子类未实现 + initialize() 方法时,会调用父类 + initialize() 方法,子类实现 + initialize() 方法时,会覆盖父类 + initialize() 方法;
  • 当有多个 Category 都实现了 + initialize() 方法,会覆盖类中的方法,只执行一个(会执行Compile Sources 列表中最后一个 Category+ initialize() 方法)。

- init()

  • TestClass 和子类分别实现 -init()方法
    TestClassSubClass *subClass1 = [[TestClassSubClass alloc] init];
    TestClassSubClass *subClass2 = [[TestClassSubClass alloc] init];
    TestClassSubClass *subClass3 = [[TestClassSubClass alloc] init];
    TestClassSubClass *subClass4 = [[TestClassSubClass alloc] init];
    TestClassSubClass *subClass5 = [[TestClassSubClass alloc] init];

image.png
子类初始化时,会先调用父类的 -init() 方法,然后调用自身的 -init() 方法,并且每次初始化时都会调用

  • 只在 TestClass 实现 -init() 方法

    调用结果如下
    image.png
    我们发现,子类未实现 -init() 方法时,每初始化一个对象,只会调用一次父类的 -init() 方法

总结:
  • +load()+initialize() 都会在实例化对象之前调用,前者是在 main() 函数之前,后者是在 main() 函数之后;
  • +load()+initialize() 方法都不会显式的调用父类的方法而是自动调用,即使子类没有 +initialize() 方法也会调用父类的方法,+load() 方法不会调用父类;
  • +load()+initialize() 方法内部使用了锁,因此他们是线程安全的,实现时要尽可能简单,避免线程阻塞,不要再次使用锁;
  • +load() 方法常用来 method swizzle+initialize() 常常用于初始化全局变量和静态变量。
2019-07-29 09:32:00 weixin_30650859 阅读数 12
原文链接

 

对于 iOS 开发者而言,+load()+initialize()-init() 方法应该并不陌生,但是,对于这些方法的调用逻辑和顺序,可能会偶有疑惑,本文通过 demo 的方式,来探究一下这几个方法

+ load()

+load() 方法是当类或分类被添加到 Objective-C runtime 时被调用的,实现这个方法可以让我们在类加载的时候执行一些类相关的行为,子类的 +load 方法会在它的所有父类的 +load() 方法之后执行,而分类的 +load() 方法会在它的主类的 +load() 方法之后执行。但是不同的类之间的 +load()方法的调用顺序是不确定的

 
image.png

我们先创建一个 TestClass 类,然后在创建一个继承自该类的子类 TestClassSubClass,和两个 TestClass 的分类 TestClass+ZTestClass+Y,分别在这几个类中实现 +load() 方法,并打印输出,然后在 main() 中也写一个输出语句,运行程序,我们来看一下输出

 

int main(int argc, char * argv[]) {
    @autoreleasepool {
        
        NSLog(@"  %s", __func__);
        
        return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
    }
}
 
image.png

如我们所看到的,+load() 的调用是在 main() 函数之前,并且在整个 APP 运行过程中只会被调用一次,对 +load() 方法进行调用,是直接使用函数内存地址的方式 (load_method)(cls, SEL_load); 而不是使用发送消息 objc_msgSend 的方式,父类 TestClass+load()方法最先被调用,而后是子类和分类,对于多个分类的 +load() 的调用顺序的先后,取决于编译顺序,测试一下,我们在 Bulid Phases->Compile Sources 调整分类的编译顺序

 
image.png

 

 

 
image.png

会看到 TestClass+Z+load() 方法先于 TestClass+Y 被调用

 

结论:
  • +load() 方法的调用是在 main() 函数之前,并且不需要主动调用,程序启动会把所有的文件加载,文件如果重写了 +load() 方法,主类、子类、分类都会加载调用 +load() 方法;
  • 主类与分类的加载顺序是: 主类优先于分类加载,无关编译顺序;
  • 分类间的加载顺序取决于编译的顺序: 先编译先加载,后编译则后加载;
  • 优先顺序: (父类 > 子类 > 分类)
  • 因为 +load() 是在 main() 函数之前调用,所以在这个方法里面不要作耗时操作或者阻塞的操作,会影响启动速度;
  • 不要做对象的初始化操作,因为在 main() 函数之前自动调用,+load() 方法调用的时候使用者根本就不能确定自己要使用的对象是否已经加载进来了,所以千万不能在这里初始化对象;
  • 可以根据业务需求,在 +load() 方法中进行 Method Swizzle 操作,交换方法

+ initialize()

+initialize() 方法是在类或它的子类收到第一条消息之前被调用的,这里所指的消息包括实例方法和类方法的调用,也就是说 +initialize() 方法是以懒加载的方式被调用的,如果程序一直没有给某个类或它的子类发送消息,那么这个类的 +initialize() 方法是永远不会被调用的,关于调用,我们同样用代码进行测试

  • TestClass 实现 + initialize() 方法,子类和分类中不实现,分别如下调用
      TestClass *class1 = [[TestClass alloc] init];
      TestClass *class2 = [[TestClass alloc] init];
    
//    TestClassSubClass *subClass1 = [[TestClassSubClass alloc] init];
//    TestClassSubClass *subClass2 = [[TestClassSubClass alloc] init];
//    TestClassSubClass *subClass3 = [[TestClassSubClass alloc] init];
//    TestClassSubClass *subClass4 = [[TestClassSubClass alloc] init];
//    TestClassSubClass *subClass5 = [[TestClassSubClass alloc] init];
 
image.png
    TestClass *class1 = [[TestClass alloc] init];
    TestClass *class2 = [[TestClass alloc] init];
    
    TestClassSubClass *subClass1 = [[TestClassSubClass alloc] init];
    TestClassSubClass *subClass2 = [[TestClassSubClass alloc] init];
    TestClassSubClass *subClass3 = [[TestClassSubClass alloc] init];
    TestClassSubClass *subClass4 = [[TestClassSubClass alloc] init];
    TestClassSubClass *subClass5 = [[TestClassSubClass alloc] init];
 
image.png

//    TestClass *class1 = [[TestClass alloc] init];
//    TestClass *class2 = [[TestClass alloc] init];
    
    TestClassSubClass *subClass1 = [[TestClassSubClass alloc] init];
    TestClassSubClass *subClass2 = [[TestClassSubClass alloc] init];
    TestClassSubClass *subClass3 = [[TestClassSubClass alloc] init];
    TestClassSubClass *subClass4 = [[TestClassSubClass alloc] init];
    TestClassSubClass *subClass5 = [[TestClassSubClass alloc] init];
 
image.png

会发现,不管我们创建 TestClass 几个对象,[TestClass initialize]只被调用一次,而如果创建了 TestClassSubClass 对象,无论是否创建 TestClass 对象,[TestClass initialize] 都会调用两次,可见当子类未实现 +initialize() 方法,会调用父类 +initialize() 方法。

  • TestClass 和子类中分别实现 + initialize 方法
    TestClass *class1 = [[TestClass alloc] init];
    TestClass *class2 = [[TestClass alloc] init];
    
    TestClassSubClass *subClass1 = [[TestClassSubClass alloc] init];
    TestClassSubClass *subClass2 = [[TestClassSubClass alloc] init];
    TestClassSubClass *subClass3 = [[TestClassSubClass alloc] init];
    TestClassSubClass *subClass4 = [[TestClassSubClass alloc] init];
    TestClassSubClass *subClass5 = [[TestClassSubClass alloc] init];
 
image.png
//    TestClass *class1 = [[TestClass alloc] init];
//    TestClass *class2 = [[TestClass alloc] init];
    
    TestClassSubClass *subClass1 = [[TestClassSubClass alloc] init];
    TestClassSubClass *subClass2 = [[TestClassSubClass alloc] init];
    TestClassSubClass *subClass3 = [[TestClassSubClass alloc] init];
    TestClassSubClass *subClass4 = [[TestClassSubClass alloc] init];
    TestClassSubClass *subClass5 = [[TestClassSubClass alloc] init];

 

 
image.png

可见,无论子类中是否实现了 + initialize() 方法,初始化都会至少去调用一次父类的 + initialize() 方法,而如果自身实现了 + initialize() 方法,那么继续调用自己的 + initialize() 方法,如果未实现,则去调用父类的 + initialize()方法

 

  • TestClass 和子类、分类中分别实现 + initialize() 方法
    TestClass *class1 = [[TestClass alloc] init];
    TestClass *class2 = [[TestClass alloc] init];
    
    TestClassSubClass *subClass1 = [[TestClassSubClass alloc] init];
    TestClassSubClass *subClass2 = [[TestClassSubClass alloc] init];
    TestClassSubClass *subClass3 = [[TestClassSubClass alloc] init];
    TestClassSubClass *subClass4 = [[TestClassSubClass alloc] init];
    TestClassSubClass *subClass5 = [[TestClassSubClass alloc] init];
//    TestClass *class1 = [[TestClass alloc] init];
//    TestClass *class2 = [[TestClass alloc] init];
    
    TestClassSubClass *subClass1 = [[TestClassSubClass alloc] init];
    TestClassSubClass *subClass2 = [[TestClassSubClass alloc] init];
    TestClassSubClass *subClass3 = [[TestClassSubClass alloc] init];
    TestClassSubClass *subClass4 = [[TestClassSubClass alloc] init];
    TestClassSubClass *subClass5 = [[TestClassSubClass alloc] init];

 

 
image.png

根据输出我们看到,之前的调用父类的 + initialize() 方法,变成了调用 TestClass+Y+ initialize() 方法,这是因为最后被编译的 TestClass+Y 中的 + initialize() 方法覆盖了主类的 + initialize() 方法

 

结论:
  • 父类的 + initialize() 方法会比子类先执行;
  • 当子类未实现 + initialize() 方法时,会调用父类 + initialize() 方法,子类实现 + initialize() 方法时,会覆盖父类 + initialize() 方法;
  • 当有多个 Category 都实现了 + initialize() 方法,会覆盖类中的方法,只执行一个(会执行Compile Sources 列表中最后一个 Category+ initialize() 方法)。

- init()

  • TestClass 和子类分别实现 -init()方法
    TestClassSubClass *subClass1 = [[TestClassSubClass alloc] init];
    TestClassSubClass *subClass2 = [[TestClassSubClass alloc] init];
    TestClassSubClass *subClass3 = [[TestClassSubClass alloc] init];
    TestClassSubClass *subClass4 = [[TestClassSubClass alloc] init];
    TestClassSubClass *subClass5 = [[TestClassSubClass alloc] init];

 

 
image.png

子类初始化时,会先调用父类的 -init() 方法,然后调用自身的 -init() 方法,并且每次初始化时都会调用

 

  • 只在 TestClass 实现 -init() 方法

    调用结果如下

     
    image.png

    我们发现,子类未实现 -init() 方法时,每初始化一个对象,只会调用一次父类的 -init() 方法

     

总结:
  • +load()+initialize() 都会在实例化对象之前调用,前者是在 main() 函数之前,后者是在 main() 函数之后;
  • +load()+initialize() 方法都不会显式的调用父类的方法而是自动调用,即使子类没有 +initialize() 方法也会调用父类的方法,+load() 方法不会调用父类;
  • +load()+initialize() 方法内部使用了锁,因此他们是线程安全的,实现时要尽可能简单,避免线程阻塞,不要再次使用锁;
  • +load() 方法常用来 method swizzle+initialize() 常常用于初始化全局变量和静态变量。

 

转载于:https://www.cnblogs.com/mustard22/articles/11262125.html

2017-08-03 10:43:22 fellow_gengxj 阅读数 144

Objective-C 有两个特殊的方法:+load和 +initialize,这两个方法在类被使用时会自动调用。但是两个方法的不同点会导致应用层面上性能的显著差异。

一、+ initialize方法和+load调用时机

首先说一下 + initialize 方法:苹果官方对这个方法有这样的一段描述:这个方法会在 第一次初始化这个类之前 被调用,我们用它来初始化静态变量。

load 方法会在加载类的时候就被调用,也就是 ios 应用启动的时候,就会加载所有的类,就会调用每个类的 + load 方法。

之后我们结合代码来探究一下 + initialize + load 两个方法的调用时机,首先是 + load

#pragram ---main函数中的代码---

#import <UIKit/UIKit.h>

#import "AppDelegate.h"

int main(int argc,char * argv[]) {

  NSLog(@"%s",__func__);

  @autoreleasepool {

      return UIApplicationMain(argc, argv, nil,NSStringFromClass([AppDelegate class]));

  }

}

#pragram ---基于NSObjectPerson---

#import "Person.h"

@implementation Person

+ (void)load{

  NSLog(@"%s",__func__);

}

+ (void)initialize{

  [super initialize];

  NSLog(@"%s %@",__func__,[selfclass]);

}

- (instancetype)init{

  if (self = [super init]) {

      NSLog(@"%s",__func__);

  }

  returnself;

}

@end

#pragram ---基于PersonSon---

#import "Girl.h"

@implementation Girl

+ (void)load{

  NSLog(@"%s ",__func__);

}

+ (void)initialize{

  [super initialize];

  NSLog(@"%s ",__func__);

}

- (instancetype)init{

  if (self = [super init]) {

      NSLog(@"%s",__func__);

  }

  returnself;

}

@end
运行程序,我们看一下输出日志:

2017-07-15 15:21:07.545 initialize[11637:334237] +[Person load]

2017-07-15 15:21:07.546 initialize[11637:334237] +[Girl load] 

2017-07-15 15:21:07.546 initialize[11637:334237] main
这说明在我并没有对类做任何操作的情况下,+load 方法会被默认执行,并且是在 main函数之前执行的。

接下来我们来查看一下 + initialize 方法,先在 ViewController中创建 Person Girl对象:

#import "ViewController.h"

#import "Person.h"

#import "Son.h"

#import "Girl.h"

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {

  [super viewDidLoad];

  Person * a = [Person new];

  Person * b = [Person new];

  Girl *c = [Girl new];

  Girl *d = [Girl new];

}

@end
下面我们来看一下输出日志:

2017-07-15 15:33:56.195 initialize[11711:342410] +[Person load]

2017-07-15 15:33:56.196 initialize[11711:342410] +[Girl load] 

2017-07-15 15:33:56.197 initialize[11711:342410] main

2017-07-15 15:33:56.259 initialize[11711:342410] +[Person initialize] Person

2017-07-15 15:33:56.259 initialize[11711:342410] -[Person init]

2017-07-15 15:33:56.259 initialize[11711:342410] -[Person init]

2017-07-15 15:33:56.259 initialize[11711:342410] +[Girl initialize] 

2017-07-15 15:33:56.260 initialize[11711:342410] -[Girl init]

2017-07-15 15:33:56.260 initialize[11711:342410] -[Girl init]
通过这个实验我们可以确定两点:

+ initialize 方法类似一个懒加载,如果没有使用这个类,那么系统默认不会去调用这个方法,且默认只加载一次;

+ initialize 的调用发生在 +init方法之前。

接下来再探究一下 + initialize 在父类与子类之间的关系,创建一个继承自 Person类的 Son类:

#pragram ---ViewController 中的代码---

#import "ViewController.h"

#import "Person.h"

#import "Son.h"

#import "Girl.h"

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {

  [super viewDidLoad];

  Person * a = [Person new];

  Person * b = [Person new];

  Son*z = [Son new];

}

@end
看一下输出日志:

2017-07-15 15:44:55.762 initialize[12024:351576] +[Person load]

2017-07-15 15:44:55.764 initialize[12024:351576] +[Son load]

2017-07-15 15:44:55.764 initialize[12024:351576] +[Girl load] 

2017-07-15 15:44:55.764 initialize[12024:351576] main

2017-07-15 15:44:55.825 initialize[12024:351576] +[Person initialize] Person

2017-07-15 15:44:55.825 initialize[12024:351576] -[Person init]

2017-07-15 15:44:55.825 initialize[12024:351576] -[Person init]

2017-07-15 15:44:55.826 initialize[12024:351576] +[Person initialize] Son

2017-07-15 15:44:55.826 initialize[12024:351576] -[Person init]
我们会发现 Person 类的 + initialize 方法又被调用了,但是查看一下是子类 Son调用的,也就是创建子类的时候,子类会去调用父类的 + initialize 方法。


二、总结

1.如果你实现了 + load 方法,那么当类被加载时它会自动被调用。这个调用非常早。如果你实现了一个应用或框架的 + load,并且你的应用链接到这个框架上了,那么  load 会在 main() 函数之前被调用。如果你在一个可加载的 bundle 中实现了 + load,那么它会在 bundle加载的过程中被调用。

2.+ initialize 方法的调用看起来会更合理,通常在它里面写代码比在 + load 里写更好。+ initialize 很有趣,因为它是懒调用的,也有可能完全不被调用。类第一次被加载时,会被调用。

3.+ initialize 不会被调用。类接收消息时,运行时会先检查 + initialize 有没有被调用过。如果没有,会在消息被处理前调用。

4.load方法的调用时机,main函数之前,先调用类中的,再调用类别中的(类别中如果有重写);

5.initialize方法的调用时机,当向该类发送第一个消息(一般是类消息首先调用,常见的是alloc)的时候,先调用类中的,再调用类别中的(类别中如果有重写);如果该类只是引用,没有调用,则不会执行initialize方法。

两者方法的共同点:自动调用父类的,不需要super操作;自动调用仅仅会调用一次(不包括外部显示调用)。


2016-09-13 23:26:07 Sico2Sico 阅读数 229

Objective-C 有两个神奇的方法:+load 和 +initialize,这两个方法在类被使用时会自动调用。但是两个方法的不同点会导致应用层面上性能的显著差异。

一、+ initialize 方法和+load 调用时机
首先说一下 + initialize 方法:苹果官方对这个方法有这样的一段描述:这个方法会在 第一次初始化这个类之前 被调用,我们用它来初始化静态变量。
load 方法会在加载类的时候就被调用,也就是 ios 应用启动的时候,就会加载所有的类,就会调用每个类的 + load 方法。
之后我们结合代码来探究一下 + initialize 与 + load 两个方法的调用时机,首先是 + load:

#pragram ---main函数中的代码---
#import <UIKit/UIKit.h>
#import "AppDelegate.h"
int main(int argc, char * argv[]) {
  NSLog(@"%s",__func__);
  @autoreleasepool {
      return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
  }
}
#pragram ---基于NSObject的Person类---
#import "Person.h"
@implementation Person
+ (void)load{
  NSLog(@"%s",__func__);
}
+ (void)initialize{
  [super initialize];
  NSLog(@"%s %@",__func__,[self class]);
}
- (instancetype)init{
  if (self = [super init]) {
      NSLog(@"%s",__func__);
  }
  return self;
}
@end
#pragram ---基于Person的Son类---
#import "Girl.h"
@implementation Girl
+ (void)load{
  NSLog(@"%s ",__func__);
}
+ (void)initialize{
  [super initialize];
  NSLog(@"%s ",__func__);
}
- (instancetype)init{
  if (self = [super init]) {
      NSLog(@"%s",__func__);
  }
  return self;
}
@end

运行程序,我们看一下输出日志:

2015-10-27 15:21:07.545 initialize[11637:334237] +[Person load]
2015-10-27 15:21:07.546 initialize[11637:334237] +[Girl load] 
2015-10-27 15:21:07.546 initialize[11637:334237] main

这说明在我并没有对类做任何操作的情况下,+load 方法会被默认执行,并且是在 main 函数之前执行的。
接下来我们来查看一下 + initialize 方法,先在 ViewController 中创建 Person 和 Girl 对象:

#import "ViewController.h"
#import "Person.h"
#import "Son.h"
#import "Girl.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
  [super viewDidLoad];
  Person * a = [Person new];
  Person * b = [Person new];
  Girl *c = [Girl new];
  Girl *d = [Girl new];
}
@end

下面我们来看一下输出日志:

2015-10-27 15:33:56.195 initialize[11711:342410] +[Person load]
2015-10-27 15:33:56.196 initialize[11711:342410] +[Girl load] 
2015-10-27 15:33:56.197 initialize[11711:342410] main
2015-10-27 15:33:56.259 initialize[11711:342410] +[Person initialize] Person
2015-10-27 15:33:56.259 initialize[11711:342410] -[Person init]
2015-10-27 15:33:56.259 initialize[11711:342410] -[Person init]
2015-10-27 15:33:56.259 initialize[11711:342410] +[Girl initialize] 
2015-10-27 15:33:56.260 initialize[11711:342410] -[Girl init]
2015-10-27 15:33:56.260 initialize[11711:342410] -[Girl init]

通过这个实验我们可以确定两点:
+ initialize 方法类似一个懒加载,如果没有使用这个类,那么系统默认不会去调用这个方法,且默认只加载一次;
+ initialize 的调用发生在 +init 方法之前。
接下来再探究一下 + initialize 在父类与子类之间的关系,创建一个继承自 Person 类的 Son类:

#pragram ---ViewController 中的代码---
#import "ViewController.h"
#import "Person.h"
#import "Son.h"
#import "Girl.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
  [super viewDidLoad];
  Person * a = [Person new];
  Person * b = [Person new];
  Son*z = [Son new];
}
@end

看一下输出日志:

2015-10-27 15:44:55.762 initialize[12024:351576] +[Person load]
2015-10-27 15:44:55.764 initialize[12024:351576] +[Son load]
2015-10-27 15:44:55.764 initialize[12024:351576] +[Girl load] 
2015-10-27 15:44:55.764 initialize[12024:351576] main
2015-10-27 15:44:55.825 initialize[12024:351576] +[Person initialize] Person
2015-10-27 15:44:55.825 initialize[12024:351576] -[Person init]
2015-10-27 15:44:55.825 initialize[12024:351576] -[Person init]
2015-10-27 15:44:55.826 initialize[12024:351576] +[Person initialize] Son
2015-10-27 15:44:55.826 initialize[12024:351576] -[Person init]

我们会发现 Person 类的 + initialize 方法又被调用了,但是查看一下是子类 Son 调用的,也就是创建子类的时候,子类会去调用父类的 + initialize 方法。

二、总结
如果你实现了 + load 方法,那么当类被加载时它会自动被调用。这个调用非常早。如果你实现了一个应用或框架的 + load,并且你的应用链接到这个框架上了,那么 + load 会在 main() 函数之前被调用。如果你在一个可加载的 bundle 中实现了 + load,那么它会在 bundle 加载的过程中被调用。
+ initialize 方法的调用看起来会更合理,通常在它里面写代码比在 + load 里写更好。+ initialize 很有趣,因为它是懒调用的,也有可能完全不被调用。类第一次被加载时,
+ initialize 不会被调用。类接收消息时,运行时会先检查 + initialize 有没有被调用过。如果没有,会在消息被处理前调用。

文/Mitchell(简书作者)
原文链接:http://www.jianshu.com/p/9368ce9bb8f9
著作权归作者所有,转载请联系作者获得授权,并标注“简书作者”。