iOS load和initialize的区别

可能有些还不清楚load和initialize的区别,下面简单说一下:

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

initialize方法的调用时机,当向该类发送第一个消息(一般是类消息首先调用,常见的是alloc)的时候,先调用类中的,再调用类别中的(类别中如果有重写);如果该类只是引用,没有调用,则不会执行initialize方法。
两者方法的共同点:自动调用父类的,不需要super操作;自动调用仅仅会调用一次(不包括外部显示调用).

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

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

代码演示:

#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

输出日志:

2017-07-07 09:28:36.535 initialize[1572:27457]] +[Person load]
2017-07-07 09:28:36.535 initialize[1572:27457]] +[Girl load]
2017-07-07 09:28:36.535 initialize[1572:27457]] 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 * p1 = [Person new];
  Person * p2 = [Person new];
  Girl *c1 = [Girl new];
  Girl *c2 = [Girl new];
}
@end

输出日志:

2017-07-07 09:34:57.134 initialize[1840:100060] +[Person load]
2017-07-07 09:34:57.135 initialize[1840:100060] +[Girl load]
2017-07-07 09:34:57.136 initialize[1840:100060] main
2017-07-07 09:34:57.198 initialize[1840:100060] +[Person initialize] Person
2017-07-07 09:34:57.198 initialize[1840:100060] -[Person init]
2017-07-07 09:34:57.198 initialize[1840:100060] -[Person init]
2017-07-07 09:34:57.198 initialize[1840:100060] +[Girl initialize]
2017-07-07 09:34:57.199 initialize[1840:100060] -[Girl init]
2017-07-07 09:34:57.199 initialize[1840:100060] -[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 * p1 = [Person new];
  Person * p2 = [Person new];
  Son*s = [Son new];
}
@end

输出日志:

2017-07-07 09:50:14.140 initialize[1893:109979] +[Person load]
2017-07-07 09:50:14.142 initialize[1893:109979]  +[Son load]
2017-07-07 09:50:14.142 initialize[1893:109979]  +[Girl load]
2017-07-07 09:50:14.142 initialize[1893:109979]  main
2017-07-07 09:50:14.203 initialize[1893:109979]  +[Person initialize] Person
2017-07-07 09:50:14.203 initialize[1893:109979] -[Person init]
2017-07-07 09:50:14.203 initialize[1893:109979]] -[Person init]
2017-07-07 09:50:14.204 initialize[1893:109979] +[Person initialize] Son
2017-07-07 09:50:14.204 initialize[1893:109979] -[Person init]

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

这是因为在创建子类对象时,首先要创建父类对象,所以会调用一次父类的initialize方法,然后创建子类时,尽管自己没有实现initialize方法,但还是会调用到父类的方法。

虽然initialize方法对一个类而言只会调用一次,但这里由于出现了两个类,所以调用两次符合规则,但不符合我们的需求。正确使用initialize方法的姿势如下

// In Person.m
+ (void)initialize {
    if (self == [Person class]) {
        NSLog(@"Initialize Person, caller Class %@", [self class]);
    }
}

加上判断后,就不会因为子类而调用到自己的initialize方法了.

总结:

  1. loadinitialize方法都会在实例化对象之前调用,以main函数为分水岭,前者在main函数之前调用,后者在之后调用。这两个方法会被自动调用,不能手动调用它们。
  2. loadinitialize方法都不用显示的调用父类的方法而是自动调用,即使子类没有initialize方法也会调用父类的方法,而load方法则不会调用父类。
  3. load方法通常用来进行Method Swizzle,initialize方法一般用于初始化全局变量或静态变量。
  4. loadinitialize方法内部使用了锁,因此它们是线程安全的。实现时要尽可能保持简单,避免阻塞线程,不要再使用锁。
时间: 2024-08-01 09:14:19

iOS load和initialize的区别的相关文章

Objective C类方法load和initialize的区别

它们的特别之处,在于iOS会在运行期提前并且自动调用这两个方法,而且很多对于类方法的规则(比如继承,类别(Category))都有不同的处理. 先来看看NSObject Class Reference里对这两个方法说明: +(void)initialize The runtime sends initialize to each class in a program exactly one time just before the class, or any class that inherit

类方法load和initialize的区别

1.+load方法当类或分类添加到object-c runtime时被调用,子类的+load方法会在它所有父类的+load方法之后执行,而分类的+load方法会在它的主类的+load方法之后执行.但不同的类之间的+load方法的调用顺序是不确定的,所以不要在此方法中用另一个类. 2.+load方法不像普通方法一样,它不遵循那套继承规则.如果某个类本身没有实现+load方法,那么不管其它各级超类是否实现此方法,系统都不会调用.+load方法调用顺序是:SuperClass -->SubClass

IOS杂笔- 7(类方法load与initialize的区别 浅析)

在介绍两种类方法之前,NSObject Class Reference里对这两个方法说明: +(void)initialize The runtime sends initialize to each class in a program exactly one time just before the class, or any class that inherits from it, is sent its first message from within the program. (Th

load和initialize的区别

initialize和load都能达到这个效果:为什么选择load? 在子类没有实现initialize时候,父类的initialize会执行多次,假如在这里做替换就会出现偶数次替换,方法替换失效的问题: 类别中实现了initialize会覆盖类中的方法,如果有多个类别都在initialize中做处理的话,那么只有一个会生效其他都会失效,具体哪个生效看compile source中哪个在最后. 以上这两个副作用,load都没有,所以还是选择在load中处理,虽然load会很微弱的影响启动时间.

NSObject的load和initialize方法

load和initialize的共同特点 在不考虑开发者主动使用的情况下,系统最多会调用一次 如果父类和子类都被调用,父类的调用一定在子类之前 都是为了应用运行提前创建合适的运行环境 在使用时都不要过重地依赖于这两个方法,除非真正必要 load和initialize的区别 load方法 调用时机比较早,运行环境有不确定因素.具体说来,在iOS上通常就是App启动时进行加载,但当load调用的时候,并不能保证所有类都加载完成且可用,必要时还要自己负责做auto release处理.对于有依赖关系的

iOS load方法与initialize方法

在 iOS 开发中,我们经常会使用 +load 方法来做一些在 main 函数之前的操作,比如方法交换(Method Swizzle)等.现在分析一下load方法跟initialize方法的调用顺序以及区别. 1.先看下load方法 尝试定义一个继承自 NSObject 的 Person 类,并对其添加两个分类 Life 和 Work:再定义一个 Student 类继承自 Person,并对其添加 School 分类.在以上所有类和分类中,均实现 +load: #import "Person.h

iOS中 性能优化之浅谈load与initialize

一. +load 源码分析 extern bool hasLoadMethods(const headerType *mhdr); extern void prepare_load_methods(const headerType *mhdr); void load_images(const char *path __unused, const struct mach_header *mh) { // Return without taking locks if there are no +lo

iOS Load方法 和 initialize方法的比较

一.load方法特点: 1. 当类被引用进程序的时候会执行这个函数 2.一个类的load方法不用写明[super load],父类就会收到调用,并且在子类之前. 3.Category的load也会收到调用,但顺序上在主类的load调用之后. 二.initialize方法特点: 1. initialize的自然调用是在第一次主动使用当前类的时候 2.和load不同,即使子类不实现initialize方法,会把父类的实现继承过来调用一遍.注意的是在此之前,父类的方法已经被执行过一次了,同样不需要su

细说OC中的load和initialize方法

OC中有两个特殊的类方法,分别是load和initialize.本文总结一下这两个方法的区别于联系.使用场景和注意事项.Demo可以在我的Github上找到——load和initialize,如果觉得有帮助还望点个star以示支持,总结在文章末尾. load 顾名思义,load方法在这个文件被程序装载时调用.只要是在Compile Sources中出现的文件总是会被装载,这与这个类是否被用到无关,因此load方法总是在main函数之前调用. 调用规则 如果一个类实现了load方法,在调用这个方法