【iOS】分类 扩展 关联对象 核心解读

311 阅读2分钟

分类 扩展 关联对象

思路

  1. 做了哪些事情?
  2. 特点
  3. 局限性
  4. 源码分析

1. 概述:

不知道源码的情况下为类添加方法,可在现有的类的基础上添加新的方法。

2. 主要作用

  1. 分解体积大的类文件
  2. 声明私有方法
  3. 把Framework的私有方法公开
  4. 模拟多继承

3. 底层实现

struct category_t {
    const char *name;
    classref_t cls;
    struct method_list_t *instanceMethods;
    struct method_list_t *classMethods;
    struct protocol_list_t *protocols;
    struct property_list_t *instanceProperties;
    // Fields below this point are not always present on disk.
    struct property_list_t *_classProperties;

    method_list_t *methodsForMeta(bool isMeta) {
        if (isMeta) return classMethods;
        else return instanceMethods;
    }

    property_list_t *propertiesForMeta(bool isMeta, struct header_info *hi);
};

从category结构可以看出:

  1. 可以添加实例方法,类方法,协议,添加实例属性,类属性(但这里的属性不会自动生成实例变量和对应的get,set方法,需要通过关联对象来实现)
  2. 不可以添加实例变量

加载调用栈

_objc_init ->map_2_images 镜像->map_images_nlock -> 
_read_images->remethodizeClass

把category的实例方法、协议以及属性添加到类上 把category的类方法和协议添加到类的metaclass上

说明: 在remethodizeClass内部核心方法是:attachCategories attachLists: 将含有mcount个元素 的mlists拼接到rw的methods上

特点:

运行时决议 可为系统类添加分类

多总结 多看源码

关联对象

提供了以下API:

// 1. 添加关联对象
void objc_setAssociatedObject(id object, const  void* key, id value, objc_AssociationPolicy policy)

// 2. 获得关联对象
id objc_getAssociatedObject(id object, const void* key)

// 3. 移除所有的关联对象
void objc_removeAssociatedObjects(id object)

其中policy属性,是一个枚举值,常见修饰词。 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LoD0y0l3-1578018300136)(media/15779461828350/15779542321735.jpg)]

关联对象底层实现依赖四个核心对象: AssocationManager AssocationHashMap objectAssociationMap ObjectAssociation AssocationManager里面存储着某个对象的关联对象Map表,即ObjectAssociationMap,这个表存储了多个关联对象,objectAssociationMap就是我们添加的关联对象.

实现原理

关联本质 AssociationManager管理并在AssociationHashMap存储 所有对象的关联内容都在统一全局容器中。

扩展

定义: Extension是Category的一个特例,类扩展与分类只少了分类的名称,所以又称之为匿名分类。 作用 :

  1. 声明私有属性
  2. 声明私有方法
  3. 声明私有成员变量

特点: 编译时决议

只以声明的形式存在,多数情况下寄生于宿主类中,不能为系统类添加扩展

特点:

  1. 编译时决议
  2. 不能为系统类添加扩展

因为运行期,对象的内部布局已经确定,如果添加实例变量会破坏类的内部布局,这对编译性语言是灾难性的。