iOS晋级知识汇总(二)runtime

Runtime

数据结构

  • objc_object
  • objc_class
  • isa指针
  • method_t

objc_object id == objc_object

  • isa_t
  • 关于isa操作相关
  • 弱引用相关
  • 关联对象相关
  • 内存管理相关

objc_class class == objc_class 继承于objc_object

Class superClass

cache_t cache

  • 快速查找方法执行函数
  • 可增量扩展的哈希表结构
  • 局部性原理的最佳应用
Cache_t.png

class_data_bits_t bits

- class\_data\_bits\_t主要是对class_rw_t的封装
- class\_rw\_t代表了类相关的读写信息、对class\_ro\_t的封装

class_rw_t

  • class_ro_t 代表了类相关的只读信息
  • protocols
  • properties
  • methods
class_rw_t.png

class_ro_t

Class_ro_t.png

isa指针

  • 指针型isa 的值代表Class的地址
  • 非指针型isa 的值的部分代表Class的地址
  • 产生这两种的初衷:我们在寻址实际上30~40位数就可以保证我们寻找到所有class的地址,多出来的位可以存储一些别的内容,来达到节省内存的目的
  • 指向问题:
    • 关于对象,其指向类对象
    • 关于类对象,其指向元类对象
    • 如果是实例方法从类对象查找,如果是类方法从元类对象查找
isa指针.png

method_t

method_t.png

const char * types

type Encodings技术

Type Encoding.png

数据结构总结

Runtime数据结构.png

对象、类对象、元类对象

  • 类对象存储实例方法列表等信息

  • 元类对象存储类方法类表等信息

  • 类对象和元类对象都是objc_class数据结构,由于继承了objc_object数据结构所以才有isa指针,

  • 所以才能实例对象找到类对象访问它的实例方法列表等信息,

  • 类对象通过isa可以找到元类对象访问类方法列表等信息

  • 元类对象的isa指针(包含根元类对象)都指向根元类对象

  • 根元类对象的superclass指向的根类对象

    • 当在跟类中的类方法没找到,会指向根类对象中去查找它的同名的实例方法

消息传递过程

实例方法消息传递过程

1、 调用了一个实例对象A对象的实例方法
2、 通过A实例对象的isa指针找到它的类对象,类对象中遍历方法列表去查找同名的方法实现,找到后Runtime发送消息调用
3、 如果没有找到就会根据superclass指针指向的父类对象,并查找其方法列表。。。直到根类对象中的方法列表,如果找到Runtime发送消息调用,如果到根类对象还没有找到就会返回nil

类方的消息传递过程

1、 调用一个类对象的类方法。
2、 通过类对象的isa指针找到元类对象,元类对象中遍历方法列表查找同名的类方法是心啊,找到后直接调用
3、如果没有找到就会通过superclass指针指向父元类对象,并查找其类方法列表。。。直到根元类对象中的类方法列表,如果找到直接调用,如果没有找到进入到消息转发
4、根元类对象如果没有找到会superclass会指向根类对象,并查找同名的实例方法,如果找到直接调用,如果没有找到返回nil

消息传递

消息传递.png
消息传递Supr.png
消息传递流程.png

1、缓存查找

例: 给定值是SEL 目标值是对应bucket_t的IMP。

  • 首先给定的函数选择器通过一个函数来映射出bucket_t在数组当中位置,这个过程是hash查找
  • 哈希查找实际上,通过给定的一个值比如说方法的选择器经过哈希函数的算法酸楚的值实际上就是给定值在对应数组当中所对应的索引位置。
    • f(key) = key & mask
    • 通过哈希查 解决查找效率的问题
    • 通过哈希查找,找到对应的bucket_t,就可以拿到IMP

2、当前类中查找

对于已排序好的列表,采用二分查找算法查找方法对应执行函数
对于没有排序的列表,采用一般遍历查找方法对应执行函数

3、父类逐级查找

父类逐级查找的过程.png

消息转发

消息转发.png

Method-Swizzling

MethodSwizzling.png
Method method1 = class_getInstanceMethod(self, @selector(test));
Method method2 = class_getInstanceMethod(self, @selector(Mytest));
method_exchangeImplementations(method1, method2);

动态添加方法

编译的时候没有这个方法,运行时有这个方法需要调用performSelector方法,在消息转发中的第一次处理函数resolveInstanceMethod动态添加DoThings:Num:方法

+ (BOOL)resolveInstanceMethod:(SEL)sel{

    NSLog(@"%@",NSStringFromSelector(sel));

    if(sel == @selector(DoThings:Num:)){
        class_addMethod([self class], sel, (IMP)MyMethodIMP, "v@:");
        return YES;
    }

    return  [super resolveInstanceMethod:sel];
}

void MyMethodIMP(id self,SEL _cmd,NSString * name,NSInteger num){
    
    NSLog(@"调用了消息转发的内容");
    NSLog(@"%@",NSStringFromSelector(_cmd));
    NSLog(@"%@",name);
    NSLog(@"%ld",(long)num);
}

动态方法解析

@dynamic

  • 动态运行时语言将函数决议推迟到运行时。
    • 当我们把一个属性标示为@dynamic的时候代表着不需要编译器在编译时,为我们生成属性的setter跟getter方法的具体实现,而在在具体运行时我们调用了setter、geter方法的时候,再去添加具体的实现。
    • 这种功能也只有动态运行时特性的语言支持
  • 编译时语言在编译期进行函数决议

面试题

nsobject有父类吗?

没有nsobject是根类

当在跟类中的类方法没找到,但是有同名的实例方法实现,那么会不会崩溃?会不会产生实际的调用?

由于根元类对象的superclass指针指向了根类对象,去查找实例同名的实例方法,如果找到就会执行同名的实例方法调用

下图中打印的是什么?

笔试题1.png
 [self class]会转化成     
 objc_msgSend(<#id  _Nullable self#>, <#SEL  _Nonnull op, ...#>)
 phone的实例对象,[self class],通过isa找到phone类对象,phone类对象是没有class的,通过superclass找到父类的。。。直到查找到根类nsobject,有calss的实现,打印出来的自然是phone
 
 [super class]会转化成
 objc_msgSendSuper(<#struct objc_super * _Nonnull super#>, <#SEL  _Nonnull op, ...#>)
 
 objc_msgSendSuper实际的接收者仍然是phone的这个实例对象,objc_msgSendSuper传递的含义,从phone的这个实例对象的父类开始查找,  直到查找到根类nsobject有class的实现,所以打印出来的结果还是phone
 

打印结果都是phone

对页面的进出添加进出信息

使用MethodSwizzling来交换viewDidLoadviewWillAppear,在替换代码中添加一些埋点操作

[obj foo]和objc_msgSend()函数之间有什么关系?

  • 向 obj对象发送一条foo的消息,[obj foo]在编译期处理以后就变成了objc_msgSend(obj,@selector(foo))
  • 由于没有参数,所以 objc_msgSend函数调用只有2个参数
  • 然后就开始了runtime的消息传递过程

runtime如何通过Selector找到对应的IMP地址的?

  • 查找当前实例所对应类对象的缓存,是否有selelctor对应imp实现如果缓存命中了,
    我们就把命中的缓存函数返回给调用方。
  • 如果缓存没有就去当前类的方法列表查找selector对应的imp实现
  • 当前类如果没有命中,就根据当前类的superclass逐级查找父类的方法列表。。。直到根类对象,直到查到selector方法的imp实现

能否向编译后的类中增加实例变量?

class_ro_t ro代表的是readonly

编译后的类是无法添加实例变量的。

能否向动态添加的类中增加实例变量?

可以的,动态添加的这个类过程当中只要在它调用注册方法之前去完成实例变量的添加就是可以实现的

消息传递机制

当我们在消息传递的过程中如何通过缓存的方法查找?

isa指针的含义?

  • 非指针类型 isa值的部分代表calss地址
  • 指针类型isa 代表class地址
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,294评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,780评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,001评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,593评论 1 289
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,687评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,679评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,667评论 3 415
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,426评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,872评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,180评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,346评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,019评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,658评论 3 323
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,268评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,495评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,275评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,207评论 2 352

推荐阅读更多精彩内容

  • 分类 用分类干了什么事情? 声明私有方法 分解体积庞大类文件 把Framework的私有方法公开 特点 运行时决议...
    struggle3g阅读 28评论 0 0
  • 1.网络 1.网络七层协议有哪些? 物理层:主要功能:传输比特流;典型设备:集线器、中继器;典型协议标准和应用:V...
    _我和你一样阅读 3,397评论 1 38
  • 1.说说OC的消息机制? OC中的方法调用其实都是转成了objc_msgSend函数的调用,给receiver(方...
    齐玉婷阅读 454评论 0 0
  • Apple相关源码地址 在 https://opensource.apple.com/source/[https:...
    Jason1226阅读 306评论 0 1
  • 1.weak和assign区别 修饰变量类型的区别: weak 只可以修饰对象。如果修饰基本数据类型,编译器会报错...
    coderjon阅读 1,017评论 0 1