小码哥iOS学习笔记第六天: initialize方法

栏目: IOS · 发布时间: 5年前

内容简介:2、3、推论: 当一个类在第一次接受消息时, 会调用他自己的
  • 定义 Person 类, 继承自 NSObject , 并实现 +(void)initialize 方法
小码哥iOS学习笔记第六天: initialize方法
  • 定义 Person 类的Category Person+Test1 , 并实现 +(void)initialize 方法
小码哥iOS学习笔记第六天: initialize方法
  • 定义 Person 类的Category Person+Test2 , 并实现 +(void)initialize 方法
小码哥iOS学习笔记第六天: initialize方法
  • 定义 Student 类, 继承自 Person , 并实现 +(void)initialize 方法
小码哥iOS学习笔记第六天: initialize方法
  • 定义 Student 类的Category Student+Test1 , 并实现 +(void)initialize 方法
小码哥iOS学习笔记第六天: initialize方法
  • 定义 Student 类的Category Student+Test2 , 并实现 +(void)initialize 方法
小码哥iOS学习笔记第六天: initialize方法

二、运行程序

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

  • main.m 中不添加任何代码, 直接运行程序
小码哥iOS学习笔记第六天: initialize方法
  • 根据结果, 可以知道任何的 +(void)initialize 方法没有被调用

2、 Person 类调用 alloc 方法

  • main.m 中调用 [Person alloc] , 底层相当于
objc_msgSend([Person class], @selector(alloc));
复制代码
小码哥iOS学习笔记第六天: initialize方法
`
  • 可以发现, Person+Test1 的代码被调用了
  • 查看一下文件的编译顺序, 可以发现 Person+Test1Person+Test2 编译的晚
小码哥iOS学习笔记第六天: initialize方法
  • 这说明在 Person 类通过消息机制调用方法时, 会通过消息机制调用 +(void)initialize 方法
objc_msgSend([Person class], @selector(initialize))
复制代码

3、 Student 类调用 alloc 方法

  • main.m 中调用 [Student alloc] , 底层相当于
objc_msgSend([Student class], @selector(alloc));
复制代码
小码哥iOS学习笔记第六天: initialize方法
  • 可以看到 [Student alloc] 调用时, 会先调用 Person 类的 +(void)initialize 方法, 在调用 Student 类的 +(void)initialize 方法

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

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

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

总结:

通过源码可以看到, 当一个类在查找方法的时候, 会先判断当前类是否初始化, 如果没有初始化就会去掉用 initialize 方法

如果这个类的父类没有初始化, 就会先调用父类的 initialize 方法, 再调用自己的 initialize 方法

类在调用 initialize 时, 使用的是 objc_msgSend 消息机制调用

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

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

  • 删除 StudentStudent+Test1Student+Test2 中的 initialize 方法
小码哥iOS学习笔记第六天: initialize方法
  • 可以看到, 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 方法

五、面试题

1、 loadinitialize 方法的区别是什么?

  • 调用方式
    • load 是根据函数地址直接调用
    • initialize 是通过 objc_msgSend 调用
  • 调用时刻
    • loadruntime 加载类、分类的时候调用(只会调用一次)
    • initialize 是类第一次接收到消息的时候调用, 每一个类只会 initialize 一次(如果子类没有实现 initialize 方法, 会调用父类的 initialize 方法, 所以父类的 initialize 方法可能会调用多次)

以上所述就是小编给大家介绍的《小码哥iOS学习笔记第六天: initialize方法》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

JAVA 2核心技术 卷Ⅰ

JAVA 2核心技术 卷Ⅰ

[美] 霍斯特曼、[美] 科奈尔 / 叶乃文、邝劲筠 等 / 机械工业出版社 / 2006-5 / 88.00元

本书是Java技术经典参考书,多年畅销不衰,第7版在保留以前版本风格的基础上,涵盖Java2开发平台标准版J2SE5.0的基础知识,主要内容包括面各对象程序设计、反射与代理、接口与内部类、事件监听器模型、使用Swing UI工具箱进行图形用户界面设计,异常处理、流输入/输出和对象序列化、泛型程序设计等。 本书内容翔实、深入浅出,附有大量程序实例,极具实用价值,是Java初学者和Java程序员......一起来看看 《JAVA 2核心技术 卷Ⅰ》 这本书的介绍吧!

JS 压缩/解压工具
JS 压缩/解压工具

在线压缩/解压 JS 代码

XML、JSON 在线转换
XML、JSON 在线转换

在线XML、JSON转换工具

正则表达式在线测试
正则表达式在线测试

正则表达式在线测试