initialize方法

总结:
通过源码可以看到, 当一个类在查找方法的时候, 会先判断当前类是否初始化, 如果没有初始化就会去掉用initialize方法
如果这个类的父类没有初始化, 就会先调用父类的initialize方法, 再调用自己的initialize方法
类在调用initialize时, 使用的是objc_msgSend消息机制调用

一、代码准备Demo地址

  • 定义Person类, 继承自NSObject, 并实现+(void)initialize方法
initialize方法_第1张图片
image.png
  • 定义Person类的CategoryPerson+Test1, 并实现+(void)initialize方法
initialize方法_第2张图片
image.png
  • 定义Person类的CategoryPerson+Test2, 并实现+(void)initialize方法
initialize方法_第3张图片
image.png
  • 定义Student类, 继承自Person, 并实现+(void)initialize方法
initialize方法_第4张图片
image.png
  • 定义Student类的CategoryStudent+Test1, 并实现+(void)initialize方法
initialize方法_第5张图片
image.png
  • 定义Student类的CategoryStudent+Test2, 并实现+(void)initialize方法
image.png

二、运行程序

1、不主动调用任何代码, 运行程序

  • main.m中不添加任何代码, 直接运行程序
initialize方法_第6张图片
image.png
  • 根据结果, 可以知道任何的+(void)initialize方法没有被调用

2、Person类调用alloc方法

  • main.m中调用[Person alloc], 底层相当于
objc_msgSend([Person class], @selector(alloc));
复制代码
initialize方法_第7张图片
image.png

`

  • 可以发现, Person+Test1的代码被调用了
  • 查看一下文件的编译顺序, 可以发现Person+Test1Person+Test2编译的晚
initialize方法_第8张图片
image.png
  • 这说明在Person类通过消息机制调用方法时, 会通过消息机制调用+(void)initialize方法
objc_msgSend([Person class], @selector(initialize))
复制代码

3、Student类调用alloc方法

  • main.m中调用[Student alloc], 底层相当于
objc_msgSend([Student class], @selector(alloc));
复制代码
initialize方法_第9张图片
image.png
  • 可以看到[Student alloc]调用时, 会先调用Person类的+(void)initialize方法, 在调用Student类的+(void)initialize方法

推论: 当一个类在第一次接受消息时, 会调用他自己的+(void)initialize方法, 如果他有父类, 那么就会优先调用父类的+(void)initialize方法

三、查看关于类调用+(void)initialize方法的源码

  • 在源码里搜索Method class_getInstanceMethod(Class cls, SEL sel)函数
initialize方法_第10张图片
image.png
  • 找到代码lookUpImpOrNil(cls, sel, nil, NO, NO, YES);
initialize方法_第11张图片
image.png
  • 进入IMP lookUpImpOrNil(Class cls, SEL sel, id inst, bool initialize, bool cache, bool resolver)函数后, 找到IMP imp = lookUpImpOrForward(cls, sel, inst, initialize, cache, resolver);
initialize方法_第12张图片
image.png
  • 进入IMP lookUpImpOrForward(Class cls, SEL sel, id inst, bool initialize, bool cache, bool resolver)函数中
image.png
  • 可以看到有判断, 如果需要初始化, 并且类没有初始化, 那么调用_class_initialize (_class_getNonMetaClass(cls, inst));
initialize方法_第13张图片
image.png
  • 进入void _class_initialize(Class cls)函数中, 我们可以看到, 如果被传入的类有父类, 并且父类没有初始化, 会通过递归将父类传入
image.png
  • 向下可以找到代码callInitialize(cls);, 即: 调用初始化方法, 并传入类对象(如果有父类, 父类没有初始化的情况下, 会先初始化父类)
image.png
  • 进入void callInitialize(Class cls)函数, 可以看到, 底层是通过消息机制, 调用了类对象的initialize方法
image.png

总结:
通过源码可以看到, 当一个类在查找方法的时候, 会先判断当前类是否初始化, 如果没有初始化就会去掉用initialize方法
如果这个类的父类没有初始化, 就会先调用父类的initialize方法, 再调用自己的initialize方法
类在调用initialize时, 使用的是objc_msgSend消息机制调用

  • 所以, 在调用[Person alloc]方法时, 会使用消息机制调用Person类的initialize方法, 又因为Person存在两个CategoryPerson+Test1Person+Test2, 此时就看哪一个Category最后一个编译, 就会调用里面的initialize方法
  • 在调用[Student alloc]时, 会调用Student类的initialize方法, 但是因为此时父类Person还没有初始化, 所以会先调用Personinitialize方法

四、移除子类的+(void)initialize方法, 再次给子类发送消息

  • 删除StudentStudent+Test1Student+Test2中的initialize方法
initialize方法_第14张图片
image.png
  • 可以看到, Person (Test1) - initialize打印了两次, 说明Personinitialize方法被调用了两次
  • 前面已经说过, 当Student类在第一次接收消息时, 会进行初始化, 如果父类没有初始化, 会先给父类初始化
  • 所以, 第一次的Person (Test1) - initialize打印, 实际就是Person类初始化时调用的
  • 而一个类只能初始化一次, 所以第二次的打印, 实际是Student类初始化时调用的
  • Student初始化调用initialize方法时, 用的下面方式
objc_msgSend([Student class], @selector(initialize))
  • 在OC中, 使用消息机制调用类方法时, 调用顺序如下:
    • 类对象通过isa找到元类对象, 在元类对象的方法列表中查找方法, 如果有就会调用
    • 如果元类对象中没有调用的方法, 就会通过元类对象superclass找到父类元类对象, 接着父类元类对象的方法列表中查找方法, 如果有就会调用
  • 所以, Student实际上在初始化时, 调用的是objc_msgSend([Student class], @selector(initialize)), 但是因为Student并没有实现initialize方法, 所以Student调用了父类Personinitialize方法

转载文章:(防止资源地址流失,记录文章)
# 小码哥iOS学习笔记第六天: initialize方法

你可能感兴趣的:(initialize方法)