04、iOS底层探索-类的原理分析上

1、元类MetaClass

首先,先来看看是什么,在OC中其实是一个指向objc_class的结构体指针,我们先看看结构体的构造,很多在OBJC2中即将废弃(单纯参考一下大概需要什么):
image.png

现有的为:
image.png
OC中对象objc_object的定义是:
image.png
这里又涉及到一个知识点__has_feature(ptrauth_calls),我们下边再补充

OC对象有一个大家都熟悉的特性:消息发送机制

  • 原理是OC对象在发送消息时,运行时库会根据对象的isa指针,得到对象所属的类,这个类包含了这个类的所有实例方法以及指向父类的指针,以便可以找到父类的实例方法。运行时库检查这个类和其父类的方法列表,找到与消息对应的方法。编译器会将消息转换为消息函数objc_msgSend进行调用。
  • OC的类其实也是一个对象,一个对象就要有一个它属于的类,意味着类也要有一个isa指针,指向他所属的类,所以,元类就是类所属的类
    • 当你给对象发送消息时,消息是在寻找这个对象的类的方法列表。
    • 当你给类发消息时,消息是在寻找这个类的元类的方法列表。

元类定义

  • 元类就是类所属的类,提供类的通用方法列表

  • isa指向上根元类是终点:

    • 对象isa -> 类isa -> 元类isa -> 父元类isa -> 根元类isa -> 根元类
    • 根类isa -> 根元类isa
  • 继承关系上NSObject是终点:

    • 元类 -> 父元类 -> 根元类 -> 根类NSObject

image.png

__has_feature(ptrauth_calls)介绍

2、类结构分析

普通指针

image.png

  • a 和 b 为变量都指向10, 10是系统开辟的固定内存空间, 其他需要10的值的变量都可以指向内存固定生成的10
  • a 和 b 地址不一样, 这是一种拷贝, 属于值拷贝, 可发现a, b地址相差4个字节,stra、strb地址相差8个字节,这取决于a、b和stra和strb的类型

对象指针

image.png

  • p1/p2 是一级指针, 指向的 alloc 开辟空间的内存地址
  • &p1/&p2 是二级指针, 指向对象的指针的地址(0x7ffeefbff3f8, 0x7ffeefbff3f0 为对象指针)

数组指针

image.png

  • &c == &c[0] == 首地址, 其实他都是取的首地址, 数组地址其实就是数组第一个元素地址即数组名为首地址
  • &c[0]与&c[1]相差4字节, 取决于数据类型
  • 数组类型指针可以通过首地址+偏移量得到其他元素(偏移量为数组下标)
  • 移动的字节数 等于 偏移量 * 数据类型字节数, 这个根据&c[0], &c[1]看出, 两者相差4

3、类的结构内存

  • bits中存放类信息,可以通过偏移获取(32字节即0x20)class_data_bits_t bits内容

image.png

  • 计算偏移量需要分析 cache_t 大小:16字节

image.png

  • 0x20是一种整型常量的表示方式。以0x开头的整型常量,代表后续字符为16进制表达。于是0x20也就是16进制的20,即10进制的32。另外,0x20作为单字节表示,可以用于字符型变量的赋值,用于char时,其代表ascii码值0x20,即字符空格’ ‘。

好了,前期的准备工作做完了,让我们按步分析 bits 中的内容吧:

bits探索

image.png

1、根据偏移获取class_data_bits_t类型的 bits
  • x/4gx test其中首地址 0x100645940
  • 0x100645940平移32字节为0x100645960
  • 因为bitsclass_data_bits_t类型, 我们要取地址所以class_data_bits_t *类型强转一下, 变成指针地址
2、获取 bitsclass_rw_t *类型的 data
  • p $2->data()是因为struct class_data_bits_t源码(->是因为当前的是指针, 结构体的话用.)

image.png

3、分别探索 data 下的 prspertiesMethods

image.png
可看到class_rw_t(结构体)里面提供一些属性properties方法列表methods协议列表protocols的方法。

  • 打印属性列表
    1. data 中查找property_array_t类型的 属性properties
    2. properties 中查看 property_array_t(以property_t结构体为参) ,再继续查看 property_array_tt

    image.png
    image.png
    image.png

image.png

  • 打印方法列表
    1. data 中查找method_array_t类型的 方法methods
    2. methods 中查看 method_array_t(以method_t结构体为参) ,再继续查看 list_array_tt

    image.png
    image.png
    image.png

image.png

  • 打印协议列表

协议列表的list结构, 获取datap $3.protocols()即可

补充

1、objc_object VS NSObjectobjc_class VS Classdispatch_objc VS dispatch,iOS底层实现使用带objc内容进行操作

2、__has_feature(ptrauth_calls)

有些时候__has_feature(ptrauth_calls)TARGET_OS_SIMULATOR一起使用, 需要先普及ARM64e概念

// ARM64 simulators have a larger address space, so use the ARM64e\
// scheme even when simulators build for ARM64-not-e.

//ARM64模拟器有更大的地址空间,所以使用ARM64e\
//即使在为ARM64-not-e构建模拟器时也是如此。
复制代码

ARM64earm64e架构,用于Apple A12及更高版本A系列处理器 或 新型OS_SIMULATOR 模拟器的设备。

  • __has_feature(ptrauth_calls): 是判断编译器是否支持指针身份验证功能
  • ptrauth_calls 指针身份验证,针对arm64e架构;使用Apple A12或更高版本A系列处理器的设备(如iPhone XS、iPhone XS Max和iPhone XR或更新的设备)支持arm64e架构

MachOView(反编译)

image.png
Symbol Table → Symbols中可看到, 实际在底层多了个_OBJC_METACLASS(meta class : 元类)

image.png

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享