在了解类的底子结构之后,本文初步了解议论iOS 中的音讯发送,即音讯调用。
首要初步议论的是——在真实音讯调用之前,咱们会去办法缓存里面寻觅真实的函数地址,iOS供应的缓存机制用于前进效率。

For speed, objc_msgSend do数组去重es not acquire any locks when it reads metho索引符号表示的意义d caches. Instead, all cache changes are performed so that any objc_msgSend running concurrently with the c数组c言语ache mutator will not crash or hang or get an incorrect result fr变量名om the cache.

一、办法的相关结构

1.1 回顾Class结构

不管议论,什么离不开最底子的类结构,现在咱们又回到Cl索引超出矩阵维度ass结构,不过这次指针数组要注重的是办法

1.1.1 Class结构

Runtime(三)办法缓存

以上是在工作时使用到类的究竟作用,那么在编译期,其真实之前的文章中也有说到,类结构略有不同,首要在于bits里指向的是class_ro_t,而非class_rw_t

1.1.2 class_r数组公式o_t结构

Runtime(三)办法缓存

索引的作用及优缺点述的作用,呈现的是定义在类里面的办法,就是咱们写在代码里硬编码办法,而不是通过以下办法增加的指针的拼音办法:

  • 分类办法;
  • 通过工作时增加的办法;

程序在工作时,会从头安排bits里结构的内容,获取bits.data(),即class_rw_t结构,该结构是工作时的结构。

1.1.3 class_rw_t

class_rw_t在程序初步工作后,会加载分类办法,会将分类办法从头安排成下面变量名的命名规矩的结构:二维数组
Runtime(三)办法缓存

1.2 method指针c言语_t 办法结构

依据上面的class_rw_t结构,咱们可以清楚的观察到,在底层中办法的结构体是method_t,即一个办法对应一个method_t
下面是metho变量泵d_t结构体的组成。

Runtime(三)办法缓存

针对method_t的成员变量,上面论说的很清楚。

  • 该结构包含了函数指针,指向具体结束。
  • 通过types来声明该办法的回来值及参数,用于底层调用结束缓存视频兼并的校验。
  • SEL是办法名。

那么咱们要调索引超出了数组边界什么意思用一个函数,还需要处理两个问题:
第一个问题:怎样依据SEL找到函数索引有哪几种类型结束地址IMP
第二个问题:办法声明校验。

1.2.1 Type Encoding

下面咱们数组先议论第二个问题,办法声明校验,这个校验,是通过给办法指定一个编码结束的,相对应的编码如下:

Runtime(三)办法缓存

二、办法缓存

咱们继续议论上面的第一个问题——怎样依据SEL找到函数结束地址IMP
在无缓存时,找到isa指向的类结构,遍历class_rw_t中的办法列表method_array_t即可。
那么有缓存的时分呢?

2.1 窥视办法缓存

咱们要窥视缓存的结构,从源码读起。下面是源码的的次序图:

Runtime(三)办法缓存

在对源码的剖析之变量名后,咱们有以下的作用:

2.缓存视频1.1 办法缓存结构

其间bucket_t *_buckets就是存放缓存列表的结构,它实质是一个哈希表。
而哈希表中的存放的数组bucket_t的结构体。
Runtime(三)办法缓存

2.1.2 验证

验证的代码在01办法缓存根究。
Runtime(三)办法缓存

2.2 哈希表

通过代码的根究,咱们整理了下面这些哈数组函数的使用办法希表中最重指针式万用表要的节点处理

Runtime(三)办法缓存

2.2.1 哈希表的处理

上面有一些需要留心的点:

(1)hash函数

mask为缓存空间大小-1,所以hash之后必定不会跨越缓存空间大小;

static inline mask_t cache_hash(cache_key_t key, mask_t mask)
{
return (mask_t)(key & mask);
}

####(2)磕碰处理

磕碰的处理因途径罢了,在iOS下做了如下处理,其实就是简略变量类型有哪些翻开寻址来进行磕碰处理:

static inline mask_t cache_next(mask_t i, mask变量与函数_t mask) {
return i ? i-1 : mask;
}

(3)缓存扩容

缓存空间是会动态改变的,其改变如下:

voi缓存文件在哪里d cache_t::expand()
{
uint32_t oldCapacit缓存的视频怎样保存到本地y = cap变量泵acity();
//假定旧的容量大小为0,就分配4(IN索引是什么意思IT_CACHE_SIZE)
//旧容量缓存视频在手机哪里找大小不指针为0,分配当时容量的2倍
uint32_t newCapacity = oldCapacity ? oldCapacity*2 : INIT_CA缓存视频CHE_SIZE;
if ((uint32_t)(mask_t)newCapacity !变量的拼音= newCapacity) {
newCapacity = oldCa变量的拼音pacity;
}
reallocate(oldCapacity, newCapacity);
}

(4)留心点

  • mask为缓存空间大小-1,所以hash之后必定不会跨越缓存空间大小;

2.2.2 读写缓存

(1) 缓存办法

咱们看看办法缓存的哈希表指针数组,是怎样指针数组存放办法的。

  1. 传入key(**@selecto缓存视频兼并app下载r(method) **)通过hash——cache_hash取得索引index变量名数组
  2. 查看指针万用表的读法当时inde索引符号表示的意义x是否被占用
    • 假定被占用,即本次哈希冲突指针,从头进行寻址——cache_next,算出index,回到2。
  3. 假定没占用,存放到index处。

(2)查找缓存

那么又是指针的拼音怎样查找缓存的呢?

  1. 传入key(**@selector(method)缓存视频怎样转入本地视频 **)通过hash——cache_has变量名h取得索引index
  2. 依据index获取bucket_t,查看该bucket._key是否与传入的key一起。
    • 若不一起,即由于存数组公式办法时,有hash冲突,再次hash——cac变量的定义he_next,算出ind变量是什么意思ex,回到2。
  3. 假定key一起性通过,即获取该bucket._imp回来;
  4. 调用bucket._imp处的函数。

数组去重、总结

3.1 办法缓存

  1. 每个类方针都存有一个cache——办法缓存列表;
  2. cache实质是哈希表,其hash函数为:f(@selector()) = @selector() & _mask;
  3. 子类没有结束办法会调用父类的办法,并且将父类办法加入到子类自己的cache 里。

3.2 办法调用

通过上面的议论,我索引符号表示的意义们大致理解了怎样调用一个办法。
Runtime(三)办法缓存

当然,指针的拼音这并不是一个音讯发送的无缺流程,下篇文章,将会敞开根究怎样调用一数组词个办法的无缺流程之旅。

参看

链接

  1. Type Encodings
  2. A指针数学pple souce objc缓存视频变成本地视频4

示例代码

  1. 01办法缓存根究