美文网首页
Category 学习

Category 学习

作者: Tony17 | 来源:发表于2020-02-28 09:07 被阅读0次

前言

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

Category 原理

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

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

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

extension 和 Category 的区别

  • OC中的扩展没有名称(匿名),而且扩展的功能是分散原类头文件臃肿和定义不想对外曝露的部分。在编译时就会合并到原类中,所以可以添加属性,成员变量等信息。
  • 分类是对原类的扩展,由于不会改变原类结构和在运行时才会合并到原类信息中,所以不支持添加属性,成员变量等信息。

Load 方法

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

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

Load方法是可以继承的。

Initialize 方法

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

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

  • 所以如果分类实现了Initialize方法,则只会调用分类的Initialize方法,不会再调用原类的Initialize方法。
  • 如果子类没有实现Initialize方法,会调用父类的Initialize方法。
  • 如果多个子类继承自同一个父类且子类都没有实现Initialize方法,则多个子类创建的时候会多次调用父类的Initialize方法,但是每次调用的含义不同,并不是父类初始化了三次。

Load 和 Initialize 的区别

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

关联对象

常用API:

  • void objc_setAssociatedObject(id object, const void * Key, id value, objc_AssociationPolicy policy) 添加关联对象
  • id objc_getAssociatedObject(id object, const void * Key) 获取关联对象
  • void objc_removeAssociatedObjects(id object) 移除所有关联对象
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
  • 在分类中使用的时候,object 一般为self
  • const void *Key 由于只是需要一个指针,为了节约内存,所以可以直接申明一个char类型的变量,不用赋值,也可以直接使用字符串, 这个值比较灵活
  • policy 根据需要存储的值类型来做确定
  • 如果是在Category中添加属性,get方法的Key可以使用隐式函数_cmd来表示当前方法地址, set方法中使用@selector(<get方法名>)确定Key
  • Category中使用关联对象,可以间接实现Category中使用成员变量的功能。
  • 如果想取消某个关联对象,直接把该对象的关联value设置为null就可以了。
  • void objc_removeAssociatedObjects(id object)会把这个object下面的所有关联对象都移除掉

关联对象的原理

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

  • AssociationsManager
  • AssociationsHashMap
  • ObjectAssociationMap
  • ObjcAssociation
associatedObject.png

最后

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

相关文章

  • Category 学习

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

  • iOS的Category底层解析

    一 ,category简介 本文是自我学习iOSruntime的过程中学习的Category的一个自我学习和总结的...

  • iOS 学习知识点杂项

    iOS 学习知识点杂项 可能有错误 学习还得靠自己 1. Category Category(分类)主要作用是为已...

  • Category的学习

    一 简介:Category为现有的类提供了拓展性,它是category_t的结构体指针,category_t属于r...

  • category学习笔记

    1.category 是什么? 首先,新建一个NcFood类,并添加两个分类 用Clang编译成c++文件 忽略不...

  • 18/70 linux正常学习办公

    layout: "post"title: "linux正常学习办公"category: "linux"date: ...

  • iOS-底层-关联对象

    前两篇文章我们学习了关于Category的知识Category分类和load和initialize,现在再看一个问...

  • iOS开发经验(23)-category

    目录 category 1. category category简介category是Objective-C 2....

  • Category and Extension

    目录 Category category的背景和概念 category的声明及实现 category的使用 cat...

  • Category底层原理

    一 Category基本使用 二 Category的底层结构三 Category的加载处理流程四 Category...

网友评论

      本文标题:Category 学习

      本文链接:https://www.haomeiwen.com/subject/vflkhhtx.html