iOS Category实现原理 (补充)
iOS Category实现原理 (补充)
load 和 initialize
load
load方法会在程序启动就会调用,当装载类信息的时候就会调用。
- 调用顺序看一下源代码。在 objc-loadmethod.m 文件中实现
void call_load_methods(void)
{
static bool loading = NO;
bool more_categories; loadMethodLock.assertLocked(); // Re-entrant calls do nothing; the outermost call will finish the job.
if (loading) return;
loading = YES; void *pool = objc_autoreleasePoolPush(); do {
// 1. Repeatedly call class +loads until there aren't any more
// 1.调用类的 load 方法
while (loadable_classes_used > 0) {
call_class_loads();
} // 2. Call category +loads ONCE
// 2.调用分类的 load 方法
more_categories = call_category_loads(); // 3. Run more +loads if there are classes OR more untried categories
} while (loadable_classes_used > 0 || more_categories); objc_autoreleasePoolPop(pool); loading = NO;
}
通过源码我们发现是优先调用类的load方法,之后调用分类的load方法。
查看load方法的调用源码,在 objc-loadmethod.m 文件中
static void call_class_loads(void)
{
int i;
// Detach current loadable list.
struct loadable_class *classes = loadable_classes;
int used = loadable_classes_used;
loadable_classes = nil;
loadable_classes_allocated = 0;
loadable_classes_used = 0;
// Call all +loads for the detached list.
for (i = 0; i < used; i++) {
Class cls = classes[i].cls;
load_method_t load_method = (load_method_t)classes[i].method;
if (!cls) continue;
if (PrintLoading) {
_objc_inform("LOAD: +[%s load]\n", cls->nameForLogging());
}
(*load_method)(cls, SEL_load);
}
// Destroy the detached list.
if (classes) free(classes);
}
- 我们看到load方法中直接拿到load方法的内存地址直接调用方法,不在是通过消息发送机制调用。
- 所以原始类的load方法并不会被覆盖,且调用类的load方法之前会保证其父类已经调用过load方法。
initialize
当类第一次接收到消息时,就会调用initialize,相当于第一次使用类的时候就会调用initialize方法。调用子类的initialize之前,会先保证调用父类的initialize方法。如果之前已经调用过initialize,就不会再调用initialize方法了。当分类重写initialize方法时会先调用分类的方法。
- 看一下initialize的源码
void callInitialize(Class cls)
{
((void(*)(Class, SEL))objc_msgSend)(cls, SEL_initialize);
asm("");
}
由此我们发现,initialize是通过消息发送机制调用的,消息发送机制通过isa指针找到对应的方法与实现,因此先找到分类方法中的实现,会优先调用分类方法中的实现。
总结
- Category中有load方法吗?load方法是什么时候调用的?load 方法能继承吗?
- Category中有load方法,load方法在程序启动装载类信息的时候就会调用。load方法可以继承。调用子类的load方法之前,会先调用父类的load方法。
- load、initialize的区别,以及它们在category重写的时候的调用的次序。
- 调用方式:
- load是根据函数地址直接调用,initialize是通过objc_msgSend调用
- 调用时刻:
- load是runtime加载类、分类的时候调用(只会调用1次),
- initialize是类第一次接收到消息的时候调用,每一个类只会initialize一次(父类的initialize方法可能会被调用多次)
- 调用顺序:
- 先调用类的load方法,先编译那个类,就先调用load。在调用load之前会先调用父类的load方法。分类中load方法不会覆盖本类的load方法,先编译的分类优先调用load方法。
- initialize先初始化父类,之后再初始化子类。如果子类没有实现+initialize,会调用父类的+initialize(所以父类的+initialize可能会被调用多次),如果分类实现了+initialize,就覆盖类本身的+initialize调用。
iOS Category实现原理 (补充)的更多相关文章
- iOS Category实现原理
iOS Category实现原理 实现原理 我们不主动引入 Category 的头文件,Category 中的方法都会被添加进主类中.我们可以通过 - performSelector: 等方式 对 C ...
- iOS Category 添加属性实现原理 - 关联对象
iOS Category 添加属性实现原理 - 关联对象 RunTime为Category动态关联对象 使用RunTime给系统的类添加属性,首先需要了解对象与属性的关系.对象一开始初始化的时候其属性 ...
- 结合 category 工作原理分析 OC2.0 中的 runtime
绝大多数 iOS 开发者在学习 runtime 时都阅读过 runtime.h 文件中的这段代码: struct objc_class { Class isa OBJC_ISA_AVAILABILI ...
- ios category类别的使用
ios category类别的使用 Objective-C提供了一个非常灵活的类(Class)扩展机制-类别(Category).类别用于对一个已经存在的类添加方法(Methods).你只需要知道这个 ...
- iOS程序启动原理---iOS-Apple苹果官方文档翻译
本系列所有开发文档翻译链接地址:iOS7开发-Apple苹果iPhone开发Xcode官方文档翻译PDF下载地址 //转载请注明出处--本文永久链接:http://www.cnblogs.com/Ch ...
- iOS应用启动原理图解 及ARC强弱引用
iOS应用启动原理图解(红色箭头表示strong强引用,绿色箭头代表weak若引用) 只要将UI控件拖到Storyboard里控制器的大view上,Xcode会自动将这些控件以强引用的形式加入到sel ...
- iOS 应用签名原理&重签名
在苹果的日常开发中,真机测试与打包等很多流程都会牵扯到各种证书,CertificateSigningRequest,p12等.但是很多相应的开发者并不理解iOS App应用签名的原理和流程.今天着重讲 ...
- iOS多线程编程原理及实践
摘要:iOS开发中,开发者不仅要做好iOS的内存管理,而且如果你的iOS涉及多线程,那你也必须了解iOS编程中对多线程的限制,iOS主线程的堆栈大小为1M,其它线程均为512KB,且这个限制开发者是无 ...
- iOS开发·runtime原理与实践: 消息转发篇(Message Forwarding) (消息机制,方法未实现+API不兼容奔溃,模拟多继承)...
本文Demo传送门: MessageForwardingDemo 摘要:编程,只了解原理不行,必须实战才能知道应用场景.本系列尝试阐述runtime相关理论的同时介绍一些实战场景,而本文则是本系列的消 ...
随机推荐
- 动态规划专题(一) HDU1087 最长公共子序列
Super Jumping! Jumping! Jumping! 首先对于动态规划问题要找出其子问题,如果找的子问题是前n个序列的最长上升子序列,但这样的子问题不好,因为它不具备无后效性,因为它的第n ...
- Java的栈和堆
JVM的内存区域可以被分为:线程栈,堆,静态方法区(实际上还有更多功能的区域,并且这里说的是JVM的内存区域) 线程栈: 注意这个栈和数据结构中的stack有相似之处,但并不是用户态的.准确 ...
- 第一节:Java 语言基础
5分30开始 18分正式开始议题 23分01开始创建项目: 讲个面向过程,函数式的方式 byte(8) char(16) short(16) int(32) long(64) long类型或者doub ...
- python之文件的读写(1)
真的崩溃,刚写完的笔记由于点错了,现在特么又要重新写了. 崩溃呀.......... 之前的废话就不再重复了,直接进入正题吧. 今天小R 学了一天的NP课程,但是python还是不能忘得,所以晚上又 ...
- C#总结---方法的out参数和ref参数
我们知道,在c#中,当我们在一个方法中想要访问另一个方法中的变量的时候,有两种解决方案---参数和返回值.但当需要返回多个值,并且是不同类型的值的之后应该怎么办呢?解决方案可以是 (1)将所有类型数据 ...
- 参考手册(html css)
HTML CSS DOM XML DOM XML DOM Document JavaScript JavaScript RegExp JSP
- vue.eslintrc.js常用配置
vue.eslintrc.js module.exports = { root: true, env: { node: true }, extends: [ "plugin:vue/esse ...
- 简单介绍Git两种拉取代码的方式
first: 1.通过git clone 命令克隆git库中的项目 注意:通过 git clone方式克隆的代码会在服务器上自动建一个与git库名相同的文件夹,所以有两种思路,第一种就是直接在wwwr ...
- ADO学途 three day
1· 程序的根本----数据 一个程序是用来处理数据算法的具体表现,可以说没有数据,程序就没有意义.今天主 要分享在一个程序中数据的支持者SQL server的建立和使用.首先当然不可缺少SQL se ...
- 51Nod 1242 斐波那契数列的第N项(矩阵快速幂)
#include <iostream> #include <algorithm> using namespace std; typedef long long LL; ; ; ...