OC:关于Category、load、initialize的那些事你还记得吗?

简介: 这篇文章主要分析Category的实现原理,load方法和initialize方法调用方式、调用时机、调用顺序、以及他们的区别,解释 Catgory 与 class Extension 有什么区别。

接下来先来了解一下Category的加载处理过程:


一、Category本质


1、在编译时期

分类会生成一个 struct _category_t 结构体,里面存储着分类的类信息(实例方法、类方法、属性、协议)。如下:


struct _category_t {
  const char *name;// 类名称
  struct _class_t *cls;
  const struct _method_list_t *instance_methods;// 实例方法列表
  const struct _method_list_t *class_methods;// 类方法列表
  const struct _protocol_list_t *protocols;// 协议泪奔
  const struct _prop_list_t *properties;// 属性列表
};


注意:所有分类编译生成的 _category_t 结构一致,但是各自存储的类信息(实例方法、类方法、属性、协议)不同。


2、程序运行时

1、通过Runtime加载某个类的所有Category数据

2、把所有Category的方法、属性、协议数据,合并到一个大数组中(后面参与编译的Category数据,会在数组的前面)


如下图,是程序运行后 Category 的底层结构:


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);
};


3、将合并后的分类数据(方法、属性、协议),插入到类原来数据的前面。


二、+load方法


1、调用方式

根据函数地址直接调用。


2、调用时机

2.1、+load方法会在runtime加载类、分类时调用

2.2、每个类、分类的+load,在程序运行过程中只调用一次。


3、调用顺序

3.1、先调用类的+load:按照编译先后顺序调用(先编译,先调用)

3.2、调用子类的+load之前会先调用父类的+load

3.3、再调用分类的+load:按照编译先后顺序调用(先编译,先调用)


三、+initialize方法


1、调用方式

通过objc_msgSend调用。


2、调用时机

+initialize方法会在类第一次接收到消息时调用


3、调用顺序

先调用父类的+initialize,再调用子类的+initialize

(先初始化父类,再初始化子类,每个类只会初始化1次)


四、load、initialize方法的区别


1、调用方式

1.1、load是根据函数地址直接调用。

1.2、initialize是通过objc_msgSend调用。


2、调用时刻

2.1、load是runtime加载类、分类的时候调用(只会调用1次)

2.2、initialize是类第一次接收到消息的时候调用,每一个类只会initialize一次(父类的initialize方法可能会被调用多次)


3、调用顺序

1、load

1.1、 先调用类的load

a) 先编译的类,优先调用load

b) 调用子类的load之前,会先调用父类的load


1.2、再调用分类的load

a) 先编译的分类,优先调用load


2、initialize

2.1、先初始化父类

2.2、再初始化子类(可能最终调用的是父类的initialize方法)


1、如果子类没有实现+initialize,会调用父类的+initialize(所以父类的+initialize可能会被调用多次)

2、如果分类实现了+initialize,就覆盖类本身的+initialize调用


提问

1、Category的实现原理

1、在编译时,首先生成统一个 struct category_t 结构体,里面存储着分类的实例方法、类方法、属性、协议。

2、程序运行时,runtime会将 Category的数据 合并到类信息中(类对象、元类对象中)


2、Catgory 与 class Extension 区别

1、class Extension 在编译的时候,数据就已经包含在类信息中。

2、Catgory 在运行时,才会将数据合并到类信息中。


3、Category中有load方法吗?load方法是什么时候调用的?load 方法能继承吗?

1、有load方法

2、load方法在runtime加载类、分类的时候调用

3、load方法可以继承,但是一般情况下不会主动去调用load方法,都是让系统自动调用


5、Category能否添加成员变量?如果可以,如何给Category添加成员变量?

1、不能直接给Category添加成员变量,但是可以间接实现Category有成员变量的效果


相关文章
|
移动开发 Dart 前端开发
从架构到源码:一文了解Flutter渲染机制
Flutter从本质上来讲还是一个UI框架,它解决的是一套代码在多端渲染的问题。在渲染管线的设计上更加精简,加上自建渲染引擎,相比ReactNative、Weex以及WebView等方案,具有更好的性能体验。本文将从架构和源码的角度详细分析Flutter渲染机制的设计与实现。较长,同学们可收藏后再看。
8947 1
从架构到源码:一文了解Flutter渲染机制
|
JavaScript 开发工具 虚拟化
配置DevEco Studio的开发环境时,需要注意什么?
配置DevEco Studio的开发环境时,需要注意什么?
|
存储 关系型数据库 MySQL
10个案例告诉你mysql不使用子查询的原因
大家好,我是V哥。上周与朋友讨论数据库子查询问题,深受启发。为此,我整理了10个案例,详细说明如何通过优化子查询提升MySQL性能。主要问题包括性能瓶颈、索引失效、查询优化器复杂度及数据传输开销等。解决方案涵盖使用EXISTS、JOIN、IN操作符、窗口函数、临时表及索引优化等。希望通过这些案例,帮助大家在实际开发中选择更高效的查询方式,提升系统性能。关注V哥,一起探讨技术,欢迎点赞支持!
817 5
|
监控 jenkins 测试技术
持续集成/持续部署(CI/CD)的最佳实践
【6月更文挑战第19天】CI/CD最佳实践概括: 确定CI(集成早期发现错误)和CD(自动化部署)概念,选择适配团队的工具如Jenkins、GitLab CI;编写自动化测试,确保每次提交时运行;实行代码审查和质量检查;自动化构建与部署,利用容器技术;建立监控与反馈机制,快速响应问题;采用分支策略如特性分支和拉取请求;持续学习与改进流程,优化效率和质量。
1127 3
|
Dart 开发工具 Android开发
Flutter与iOS原生混合开发
Flutter与iOS原生混合开发
954 2
|
开发工具 iOS开发
解决Flutter运行报错Could not run build/ios/iphoneos/Runner.app
解决Flutter运行报错Could not run build/ios/iphoneos/Runner.app
1203 2
|
Perl
解决Cocoapods重装或更新后版本不生效的问题
解决Cocoapods重装或更新后版本不生效的问题
885 1
|
人工智能 自然语言处理 小程序
|
Android开发 C++ 开发者
Android经典实战之跨平台开发方案:Kotlin Multiplatform vs Flutter
本文对比了Kotlin Multiplatform与Flutter两大跨平台开发框架,从技术特性、性能、开发效率、UI体验、可扩展性及适用场景等维度进行了详尽分析,帮助开发者根据项目需求和技术背景选择最优方案。
2027 2
|
测试技术 Swift iOS开发
探索iOS自动化测试:使用Swift编写UI测试
【8月更文挑战第31天】在软件开发的海洋中,自动化测试是保证船只不偏离航线的灯塔。本文将带领读者启航,深入探索iOS应用的自动化UI测试。我们将通过Swift语言,点亮代码的灯塔,照亮测试的道路。文章不仅会展示如何搭建测试环境,还会提供实用的代码示例,让理论知识在实践中生根发芽。无论你是新手还是有经验的开发者,这篇文章都将是你技能提升之旅的宝贵指南。

热门文章

最新文章