OC进阶 - load | initialize

load | initialize

1 - 验证父类、当前类、子类、分类中 load/initialize 两方法的执行状况。继承关系如是 Student -> Person | Animal -> NSObject,我们在每个类中重写 load/initialize 两方法

① load 方法

// - Person.m

#import "Person.h"
@implementation Person

+(void)load{
    NSLog(@"Person load...");
}

+(void)initialize{
    NSLog(@"Person initializing...");
}

@end

// - Animal.m

#import "Animal.h"
@implementation Animal

+(void)load{
    NSLog(@"Animal load...");
}

+(void)initialize{
    NSLog(@"Animal initializing...");
}

@end

// - Student.m

#import "Student.h"
@implementation Student
+(void)load{
    NSLog(@"Student load...");
}
+(void)initialize{
    
    NSLog(@"Student initializing...");
}

@end

// - Student+Learn.m

#import "Student+Learn.h"
@implementation Student (Learn)

+(void)load{
    NSLog(@"Student+Learn load...");
}


+ (void)initialize{
    NSLog(@"Student+Learn initializing...");
}

@end

日志信息:运行程序

程序运行时编译器就会加载项目中所有的类(父类、当前类、子类、分类...),紧接着就会调用每个类的 load 方法(只调用一次)

load 方法执行顺序:父类 -> 当前类 -> 子类 -> 分类

我们知道,如果分类中所添加的方法和当前类中的方法相同,那么分类将会覆盖当前类中的方法。示例中分类 Student+Learn 已重写 load 方法,按照预想当程序启动后应该只会执行分类中的 load 方法,但为什么当前类 Student 和它的分类 Student+Learn 均执行了 load 方法 ?

接下来我们打开 Runtime 源码

打开 call_class_loads() 我们发现它是直接从自身类的内部直接去掉用 load 方法,而非采用消息传递机制

同样地不出意料的话 call_category_loads() 也是直接从自身类的内部直接去掉用 load 方法

② initialize 方法:它底层实现是消息传递。它的触发时机是当一个类对象初始化时就会调用该方法

// - ViewController.m

#import "ViewController.h"
#import "Person.h"
#import "Student.h"
#import "Student+Learn.h"
#import "Animal.h"
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
    [super touchesBegan:touches withEvent:event];
    
    Person *p1 = [Person new];
    // 调用的是分类 Student+Learn 中的初始化方法
    Student *stu1 = [[Student alloc] init];
    Animal *an1 = [Animal new];
}

日志信息:点击屏幕(只执行了分类中的初始化方法)

initialize 方法执行顺序:父类 -> 当前类 -> 子类 -> 分类

③ 代码分析:试着说出以下代码会输出什么(Person、Student 均是首次使用)

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
    [super touchesBegan:touches withEvent:event];
    [Person load];
    [Student load];

}

当点击视图时(第一次点击)

[Person load]  首先触发 Person initializing,然后再去执行 Person 中的 load 方法

[Student load] 首先触发 Student+Learn initializing,然后去执行 Student+Learn 中的 load 方法

以后的每次点击只会触发手动调用的 load 方法,因为 initialize 方法只会执行一次

 

posted on 2022-05-31 16:54  低头捡石頭  阅读(36)  评论(0编辑  收藏  举报

导航