OC中load和initialize方法

前言

最近在由于工做的缘由,空余时间相对多了一点。因此准备好好整理一下OC相关的基础知识,以便加固相关的知识点。安全

+load方法

调用时机
  1. +load方法会在runtime加载类和分类时调用;
  2. 每一个类和分类在程序运行中只调用一次+load方法;
  3. 只要是在Compile Sources中的文件总会被加载,这与这个类是否被用到无关,所以+load方法老是在main函数以前被调用。
调用顺序
  1. 执行父类的+load方法
  2. 执行当前类的+load方法
  3. 执行分类的+load方法
  4. 不一样的类之间方法调用顺序根据Compile Sources中文件的顺序来 下面咱们看下实际调用状况:
//Person.m
+ (void)load {
    NSLog(@"====== Person load function ======");
}

//Fruit.m
+ (void)load {
    NSLog(@"====== Fruit load function ======");
}

//Person子类Student
+(void)load {
    NSLog(@"======= Student load function =======");
}

//Person子类 Boy
+(void)load {
    NSLog(@"===== Boy load function =====");
}

//Person+Height分类
+(void)load {
    NSLog(@"===== Person (Height) load function =====");
}

//Person+Gender分类
+ (void)load {
    NSLog(@"======= Person (Gender) load function ========");
}
//运行结果
/*
2019-07-24 17:36:54.231549+0800 LoadDemo[10707:328172] ====== Person load function ======
2019-07-24 17:36:54.232529+0800 LoadDemo[10707:328172] ======= Student load function =======
2019-07-24 17:36:54.232701+0800 LoadDemo[10707:328172] ===== Boy load function =====
2019-07-24 17:36:54.232834+0800 LoadDemo[10707:328172] ====== Fruit load function ======
2019-07-24 17:36:54.232949+0800 LoadDemo[10707:328172] ===== Person (Height) load function =====
2019-07-24 17:36:54.233059+0800 LoadDemo[10707:328172] ======= Person (Gender) load function ========
2019-07-24 17:36:54.233225+0800 LoadDemo[10707:328172] ============== main function =========/n
*/
复制代码

若是一个类没有实现+load方法,那么就不会调用它的+load方法。在Compile Sources中,文件的排放顺讯就是其加载顺序,也就是+load方法的调用顺序。从其中也能够看出Person+load方法调用顺序优先于子类BoyStudent的顺序。同时子类中+load方法的调用顺序则是Compile Sources中文件的摆放顺序。bash

使用场景

从上面能够看出+load函数调用在main函数以前,同时+load方法时的环境很不安全,咱们应该尽可能减小+load方法的逻辑。另外一个缘由是+load的方法是线程安全的,它内部使用了锁,因此咱们应当避免线程阻塞在+load方法中。 常见的使用+load方法的场景就是Method Swizzle:函数

+ (void)load {
    Method orginalFunc = class_getInstanceMethod([self class], @selector(originalFunc));
    Method swizzleFunc = class_getInstanceMethod([self class], @selector(swizzleFunc));
    method_exchangeImplementations(orginalFunc, swizzleFunc);
}
复制代码

initialize调用

调用时机

initialize方法在第一次给某个类发送消息时调用(好比实例化一个对象),而且只会调用一次。该方法其实是一种惰性方法,也就是说若是一个类没有被用到,那它的initialize方法就不会调用。ui

调用顺序
  1. 先调用父类的initialize方法,而且即便子类没有实现initialize方法,也会调用父类方法。
  2. 建立子类,若是子类没有实现initialize方法,父类initialize方法会调用屡次。由于建立子类对象是要建立父类对象
  3. 有分类的类会调用分类实现的initialize方法,而不调用当前类的initialize方法。
//Person.m
+ (void)initialize {
    NSLog(@"===== Person initialize function =====");
}
//调用
 Student *student = [[Student alloc] init];

// Student中未实现initialize方法,打印结果
2019-07-25 15:20:51.585788+0800 LoadDemo[19894:580248] ===== Person initialize function =====
2019-07-25 15:20:51.585972+0800 LoadDemo[19894:580248] ===== Person initialize function =====

//Student中实现initialize方法,打印结果
2019-07-25 15:23:06.068990+0800 LoadDemo[19929:581522] ===== Person initialize function =====
2019-07-25 15:23:06.069200+0800 LoadDemo[19929:581522] ===== Student initialize function =====
复制代码

要避免分类为实现initialize方法,致使父类initialize方法屡次调用可使用以下方式:spa

+ (void)initialize {
    if (self == [Person class]) {
        NSLog(@"===== Person initialize function =====");
    }
}
复制代码
使用场景

在initialize中能够初始化一些静态对象线程

static NSMutableArray *emptyArray;

+ (void)initialize {
    if (self == [Person class]) {
        emptyArray = [[NSMutableArray alloc] init];
        NSLog(@"===== Person initialize function =====");
    }
}
复制代码
相关文章
相关标签/搜索