Objective-C RunTime 学习笔记 之 基础结构体
1、OC 运行期常用对象结构体
基本的结构体定义
typedef objc_class Class; /* 类 */
typedef objc_object *id; /* 各种类型,只要第一个字段为isa_t 即可,兼容Class */
1.2) isa_t 联合体定义
union isa_t {
Class cls;
uintptr_t bits; /* unsigned long 无符号长整形,8个字节 */
#if SUPPORT_NONPOINTER_ISA
# if __arm64__
struct {
uintptr_t indexed : 1;
uintptr_t has_assoc : 1;
uintptr_t has_cxx_dtor : 1;
uintptr_t shiftcls : 33; // MACH_VM_MAX_ADDRESS 0x1000000000
uintptr_t magic : 6;
uintptr_t weakly_referenced : 1;
uintptr_t deallocating : 1;
uintptr_t has_sidetable_rc : 1;
uintptr_t extra_rc : 19;
};
# elif __x86_64__
struct {
uintptr_t indexed : 1;
uintptr_t has_assoc : 1;
uintptr_t has_cxx_dtor : 1;
uintptr_t shiftcls : 44; // MACH_VM_MAX_ADDRESS 0x7fffffe00000
uintptr_t magic : 6;
uintptr_t weakly_referenced : 1;
uintptr_t deallocating : 1;
uintptr_t has_sidetable_rc : 1;
uintptr_t extra_rc : 8;
};
# else
# error unknown architecture
# endif
#endif
};
当64位下,使用 extra_rc 来存储引用计数,如果超出则同时将extra_rc的一半移到SideTable中。
1.3) objc_object/objc_class 结构体定义
/* Foundation 对象 */
struct objc_object {
private:
isa_t isa; // 仅仅定义了isa的联合体
/* ... 省略各种方法 */
} /* 类 */
struct objc_class : objc_object {
// Class ISA;
Class superclass;
cache_t cache; // formerly cache pointer and vtable
class_data_bits_t bits; // class_rw_t * plus custom rr/alloc flags
/* ...省略各种方法 */
}
可以看到无论是类还是对象,第一个字段为 isa_t ,在实例对象中指向类(存放实例变量内存布局、方法列表、属性列表、协议列表),而类则指向元类(类的方法列表、属性列表、协议列表)。class中有一个关键的结构体 class_data_bits_t
1.4) class_data_bits_t 结构体定义
struct class_data_bits_t {
// Values are the FAST_ flags above.
uintptr_t bits;
/* 不同的位域存储不同的FLAG 和 class_rw_t 结构体的指针 */
/* 省略各种方法 */
}
在bits字段中,除了指向一个运行期的结构体 class_rw_t, 还在低4位标注了一些标识
bits(低4位注明一些FAST flag(64 位)) 说明:
- a) calloc与malloc 分配的内存,在64位下,返回的有效地址为,从低到高的位顺序位 5-44位为有效值,因此,高20位与低4位为无效字段,可以通过这些字段进行存储有效值。
- #define FAST_DATA_MASK 0x00007ffffffffff8UL class_rw_t 指针地址位掩码64位下, malloc/calloc 低5位到44位为有效地址空间)
- b) 第一位如果为1(#define FAST_IS_SWIFT (1UL<<0)) 意味着是swift class
- c) 第二位如果为1(#define FAST_HAS_DEFAULT_RR (1UL<<1)) 意味着有默认的实现 retain/release/autorelease/retainCount
- d) 第三位如果为1(#define FAST_REQUIRES_RAW_ISA (1UL<<2)) 意味着类的默认的实现 alloc/allocWithZone:
1.5) class_rw_t/class_ro_t 结构体定义
struct class_rw_t {
uint32_t flags; /* 定义flag集合 */
uint32_t version; /* 类的版本,貌似元类为7,普通类为0 */
const class_ro_t *ro; /* 这个结构体存放的编译期实例变量的布局以及实例变量的size、方法列表、属性列表、协议列表 */
method_array_t methods; /* 实例方法数组 */
property_array_t properties; /* 实例属性数组 */
protocol_array_t protocols; /* 协议数组 */
Class firstSubclass;
Class nextSiblingClass;
char *demangledName; /* 类名 */
/* 省略各种方法 */
} struct class_ro_t {
uint32_t flags;
uint32_t instanceStart; /* 实例变量开始的偏移量 */
uint32_t instanceSize; /* NSObject 类需要分配的字节数 */
#ifdef __LP64__
uint32_t reserved;
#endif
const uint8_t * ivarLayout; /* 布局 */
const char * name;
method_list_t * baseMethodList; /* 本次实现方法列表 */
protocol_list_t * baseProtocols; /* 本次实例协议列表 */
const ivar_list_t * ivars; /* 本次实例变量列表 */
const uint8_t * weakIvarLayout; /*本次 弱引用变量布局 */
property_list_t *baseProperties; /* 本次属性列表 */
/* 省略各种方法 */
}
这个结构体 class_rw_t 中flags存放着运行期的一系列标识位,class_ro_t 是在编译期确定的结构,里面存放着实例变量的内存布局,这也是为什么在类定义好,不能在运行期加入实例变量的原因(通过 objc_allocateClassPair 除外,但是当调用 objc_registerClassPair 后也不允许加入实例变量),通过clang -rewrite-objc 可以看到大量的class_ro_t结构体定义,或者通过otool工具也可以查看编译后的 class_ro_t 结构。
class_rw_t 中 methods存放了所有本次定义的方法以及分类的方法,分类的方法加入到了数组的最前端,这也是为什么分类方法会覆盖掉类原始定义的方法,因为在通过LC_XXX命令加载镜像时,_read_images 会先加载类定义的方法,然后在加载分类的方法。
实验: 使用 otool -o 输出 iOS app 段,可以明显看到 class_ro_t 定义
/* 使用otool -o 输出iOS app 中的段 */
Contents of (__DATA,__objc_classlist) section
014a8048 0x16a2200
isa 0x16a2214
superclass 0x16ba2b0
cache 0x0
vtable 0x0
data 0x14ace5c (struct class_ro_t *)
flags 0x90
instanceStart 4
instanceSize 8
ivarLayout 0x0
name 0x1108c74 HNAHiHomePageControl
baseMethods 0x14acdf8 (struct method_list_t *)
entsize 12
count 4
name 0x1036ddc initWithFrame:
types 0x11248c5 @24@0:4{CGRect={CGPoint=ff}{CGSize=ff}}8
imp 0xaa21
name 0x1036e6a drawRect:
types 0x11248ee v24@0:4{CGRect={CGPoint=ff}{CGSize=ff}}8
imp 0xaa6d
name 0x1036e74 dotCornerRadius
types 0x1124917 f8@0:4
imp 0xacf1
name 0x1036e84 setDotCornerRadius:
types 0x112491e v12@0:4f8
imp 0xad01
baseProtocols 0x0
ivars 0x14ace30
entsize 20
count 1
offset 0x168eda8 4
name 0x1036e98 _dotCornerRadius
type 0x1124928 f
alignment 2
size 4
weakIvarLayout 0x0
baseProperties 0x14ace4c
entsize 8
count 1
name 0x117a230 dotCornerRadius
attributes 0x117a240 Tf,N,V_dotCornerRadius
Meta Class
isa 0x0
superclass 0x16ba2c4
cache 0x0
vtable 0x0
data 0x14acdd0 (struct class_ro_t *)
flags 0x91 RO_META
instanceStart 20
instanceSize 20
ivarLayout 0x0
name 0x1108c74 HNAHiHomePageControl
baseMethods 0x0 (struct method_list_t *)
baseProtocols 0x0
ivars 0x0
weakIvarLayout 0x0
baseProperties 0x0
Objective-C RunTime 学习笔记 之 基础结构体的更多相关文章
- Go学习笔记07-结构体与方法
Go学习笔记07-结构体与方法 Go语言 面向对象 结构的定义与创建 面向对象 Go语言只支持封装,不支持继承和多态. Go语言中只有struct,即结构体:没有class. 结构的定义与创建 pac ...
- C语言学习笔记10-结构体、枚举、联合体
C语言学习笔记10-结构体.枚举.联合体 待传
- 我的runtime学习笔记
0.简介: OC方法不同于C语言函数,属于动态调用过程,在编译的时候并不能决定真正调用哪个函数,只有在真正运行的时候才会根据函数的名称找到对应的函数来调用. 至于其他理论上的东西不必讲太多,编程讲的就 ...
- Object C学习笔记20-结构体
在学习Object C中的过程中,关于struct的资料貌似非常少,查阅了C方面的资料总结了一些学习心得! 一. 定义结构 结构体是一种数据类型的组合和数据抽象.结构体的定义语法如下: struct ...
- C#学习笔记之结构体
1.概述 结构是一种与类相似的数据类型,不过它较类更为轻量,一般适用于表示类似Point.Rectangle.Color的对象.基本上结构能办到的类全都能办到,但在某些情况下使用结构更为合适,后面会有 ...
- Object C学习笔记20-结构体(转)
在学习Object C中的过程中,关于struct的资料貌似非常少,查阅了C方面的资料总结了一些学习心得! 一. 定义结构 结构体是一种数据类型的组合和数据抽象.结构体的定义语法如下: struct ...
- contiki学习笔记---process结构体
process,字面意义,进程,看看它的结构 struct process { struct process *next; #if PROCESS_CONF_NO_PROCESS_NAMES #def ...
- runtime学习笔记
获取属性objc_property_t * propertys = class_copyPropertyList(clazz, &outCount); 获取属性名NSString * key ...
- 《PHP7底层设计与源码实现》学习笔记2——结构体对齐
书里给了一段代码,假如有个结构体如下: struct test { char a; int b; long c; void* d; int e; cha ...
随机推荐
- Direct3D 11 Tutorial 1: Basics_Direct3D 11 教程1:基础
Github-LearnDirectX-DX3D11 tutorial01 概述 在这第一篇教程中,我们将通过介绍创建最小Direct3D应用程序所必需的元素.每一个Direct3D应用程序必需拥有这 ...
- Shell常见问题整理
1. 使用shell进行程序设计的原因是什么? 可以快速.简单的完成编程,非常适合于编写一些执行相对简单的任务的小工具.如果有一个简单的构想,可以通过它检查自己的想法是否可行.还可以使用shell对进 ...
- Windows10 + IntelliJ IDEA 2017.3.2 + wamp2e + xdebug 调试 配置
一.环境 系统: windows10 WampServer: wampserver2.2e-php5.3.13-httpd2.2.22-mysql5.5.24-32b.exe IDE: Intel ...
- 用 wait-notify 写一段代码来解决生产者-消费者问题
在同步块中调用 wait() 和 notify()方法,如果阻塞,通过循环来测试等待条件.请参考答案中的示例代码. [生产者] import java.util.Vector; import java ...
- K8s(7)-安装Web UI
仪表板是基于Web的Kubernetes用户界面.您可以使用仪表板将容器化应用程序部署到Kubernetes集群,对容器化应用程序进行故障排除,以及管理集群资源.您可以使用仪表板来概述群集上运行的应用 ...
- OpenGL——天空盒子模型
加载天空盒子的六个jpg图片,不知道为什么加载不出顶部和底部的jpg图片.没有解决. 加载来自http://www.custommapmakers.org/skyboxes.php的tga图片,没有问 ...
- 新Windows本地提权漏洞学习(CVE-2019-0841)
1.这是一个啥漏洞? 睁眼一看,妈呀本地提权,快加入本地提权漏洞利用包里,速度加入.github连接我就不发了.担心被认为是传播黑客工具,咱们在这里单纯学习一下漏洞的原理和部分源代码. 2.文件读写权 ...
- 公司中springcloud项目遇到的问题
1.更改maven的.m2下的settings.xml文件,程序就可以运行,是不是很神奇?
- share drive 无效
docker设置的share dirve怎么按都无效 试了几遍都不行,想想刚才电脑系统更新了,然后查了下百度,发现是电脑策略的问题,设置成经典的就可以了
- JAVA课程课后作业03之作业一
作业:使用类的静态字段和构造函数,可以跟踪某个类所创建对象的个数.请写一个类,在任何时候都可以向它查询“你已经创建了多少个对象?”. 代码: package TestJava; import java ...