Category 学习

2020-02-28  本文已影响0人  Tony17

前言

CategoryOC语言的基础特性之一,用于在不改变原有类结构的情况下扩展该类功能(主要是添加方法等)。

Category 原理

编译时生成Category_t的结构体,结构体中主要包括实例方法里列表、类方法列表、属性列表,在运行时把结构体中的信息合并到原类中。合并的方式为最后编译的分类信息在最前面,原类中的信息在最后面,所以如果多个分类都定义了同一个方法(名称相同),则会执行最后编译的那个分类中的方法 。往原类中添加方法的步骤为:

  1. 给原类的方法列表扩容
  2. 原方法后移
  3. 分类方法占用原方法的位置(按编译顺序来,最后编译的在最前面)
category-struct.png

Category中没有办法添加属性,是因为分类的结构体中没有成员变量字段的定义,而属性是需要创建成员变量和getset方法的,虽然Category中创建属性的时候也会自动创建getset方法, 但是不会实现它, 而且没有对应的成员变量作为值的载体。所以不能实现属性的功能。

extension 和 Category 的区别

Load 方法

Load方法会在runtime加载类,分类的时候调用,每个类、分类在程序运行过程中只会调用一次。调用顺序为:

  1. 先调用父类,在调用子类
  2. 先调用原类,在按照编译顺序调用分类

Load方法是可以继承的。

Initialize 方法

在类第一次接收到消息的时候调用。先调用父类的该方法,再调用子类的该方法。

Initialize 是通过objc_msgSend调用的,特性如下:

Load 和 Initialize 的区别

  1. 调用方式
    • Load是根据函数地址直接调用
    • Initialize是通过objc_msgSend调用
  2. 调用时刻
    • Loadruntime加载类,分类时候调用一次
    • Initialize是类第一次接收到消息时候调用,每个类只会调用1次(父类的Initialize方法可能被调用多次)
  3. 调用顺序
    • Load
      1. 先调用父类的Load,在调用子类的Load
      2. 再调用分类的Load,先编译的分类优先调用
    • Initialize
      1. 先初始化父类
      2. 在初始化子类(可能最终调用的还是父类的Initialize方法)

关联对象

常用API:

objc_AssociationPolicy 修饰符
OBJC_ASSOCIATION_ASSIGN assign
OBJC_ASSOCIATION_RETAIN_NONATOMIC strong, nonatomic
OBJC_ASSOCIATION_COPY_NONATOMIC copy, nonatomic
OBJC_ASSOCIATION_RETAIN strong, atomic
OBJC_ASSOCIATION_COPY copy, atomic

关联对象的原理

关联对象的Key并不是存储在对应的类中的,由AssociationsManager统一管理并存储在AssociationsHashMap中。
核心对象:

associatedObject.png

最后

以上就是本篇的内容,势必会有一些遗漏和错误,欢迎斧正~

上一篇 下一篇

猜你喜欢

热点阅读