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 学习笔记 之 基础结构体的更多相关文章

  1. Go学习笔记07-结构体与方法

    Go学习笔记07-结构体与方法 Go语言 面向对象 结构的定义与创建 面向对象 Go语言只支持封装,不支持继承和多态. Go语言中只有struct,即结构体:没有class. 结构的定义与创建 pac ...

  2. C语言学习笔记10-结构体、枚举、联合体

    C语言学习笔记10-结构体.枚举.联合体    待传

  3. 我的runtime学习笔记

    0.简介: OC方法不同于C语言函数,属于动态调用过程,在编译的时候并不能决定真正调用哪个函数,只有在真正运行的时候才会根据函数的名称找到对应的函数来调用. 至于其他理论上的东西不必讲太多,编程讲的就 ...

  4. Object C学习笔记20-结构体

    在学习Object C中的过程中,关于struct的资料貌似非常少,查阅了C方面的资料总结了一些学习心得! 一. 定义结构 结构体是一种数据类型的组合和数据抽象.结构体的定义语法如下: struct ...

  5. C#学习笔记之结构体

    1.概述 结构是一种与类相似的数据类型,不过它较类更为轻量,一般适用于表示类似Point.Rectangle.Color的对象.基本上结构能办到的类全都能办到,但在某些情况下使用结构更为合适,后面会有 ...

  6. Object C学习笔记20-结构体(转)

    在学习Object C中的过程中,关于struct的资料貌似非常少,查阅了C方面的资料总结了一些学习心得! 一. 定义结构 结构体是一种数据类型的组合和数据抽象.结构体的定义语法如下: struct ...

  7. contiki学习笔记---process结构体

    process,字面意义,进程,看看它的结构 struct process { struct process *next; #if PROCESS_CONF_NO_PROCESS_NAMES #def ...

  8. runtime学习笔记

    获取属性objc_property_t * propertys = class_copyPropertyList(clazz, &outCount); 获取属性名NSString * key ...

  9. 《PHP7底层设计与源码实现》学习笔记2——结构体对齐

    书里给了一段代码,假如有个结构体如下: struct test {     char a;     int b;     long c;     void* d;     int e;     cha ...

随机推荐

  1. 【转】wpf 模板选择器DataTemplateSelector及动态绑定,DataTemplate.Triggers触发器的使用

    通常,如果有多个 DataTemplate 可用于同一类型的对象,并且您希望根据每个数据对象的属性提供自己的逻辑来选择要应用的 DataTemplate,则应创建 DataTemplateSelect ...

  2. windows ngix 安装 配置 使用

    参考版本nginx-1.10.3 一.常用命令 start nginx.exe                      //开启服务 nginx.exe -s stop                ...

  3. 大华等其他NVR接入海康IPC H.264方法

    有一次遇到这个问题,因为时间急,没有注意,这次一个朋友也遇到这个问题,各种百度,也没有看到答案 只好自己研究了一下,最终发现以下方式来解决 下面办法可以解决海康IPC不能能过ONVIF连接到大华等其他 ...

  4. easyui的tree节点的获取和选中

    1.设置选中tree的节点 var node = $('#tt').tree('find', 1);//找到id为”tt“这个树的节点id为”1“的对象$('#tt').tree('select', ...

  5. mysql使用druid监控配置

    近一年公司对druid使用频率越来越高了,感觉有必要了解下druid的监控配置,参考文档:https://blog.csdn.net/netdevgirl/article/details/526098 ...

  6. MISCONF Redis is configured to save RDB snapshots, but it is currently not able to persist on disk. Commands that may modify the data set are disabled, because this instance is configured to report e

    早上来到公司,线上的项目报错: Error in execution; nested exception is io.lettuce.core.RedisCommandExecutionExcepti ...

  7. C#GDI+ 绘制线段(实线或虚线)、矩形、字符串、圆、椭圆

    C#GDI+ 绘制线段(实线或虚线).矩形.字符串.圆.椭圆 绘制基本线条和图形 比较简单,直接看代码. Graphics graphics = e.Graphics; //绘制实线 )) { pen ...

  8. 关于4A网络安全管控平台控件加载失败的解决方法

    最近电脑重装系统后,到公司登录4A管控平台提示"控件加载失败","无效的参数为:Null","点击资源无任何反映"等等问题 别人的电脑用的好 ...

  9. windows 下面必备软件

    弹窗拦截软件 http://www.pc6.com/pc/tcguanggaolj/

  10. ubuntu 14.04升级python2

    http://blog.csdn.net/zahuopuboss/article/details/50927432