Objective-C底层数据结构

类的数据结构

Class(指针)

typedef struct objc_class *Class;

/*
*这是由编译器为每个类产生的数据结构,这个结构定义了一个类.
*这个结构是通过编译器在执行时产生,在运行时发送消息时使用.
*因此,一些成员改变了类型.编译器产生"char* const"类型的字符串指针替代了下面的成员变量"super_class"
*/
struct objc_class {
  struct objc_class*  class_pointer;    /* 指向元类的指针. */
  struct objc_class*  super_class;      /* 指向父类的指针. 对于NSObject来说是NULL.*/
  const char*         name;             /* 类的名称. */
  long                version;          /* 未知. */
  unsigned long       info;             /* 比特蒙板.  参考下面类的蒙板定义. */
  long                instance_size;    /* 类的字节数.包含类的定义和所有父类的定义 */
#ifdef _WIN64
  long pad;
#endif
  struct objc_ivar_list* ivars;         /* 指向类中定义的实例变量的列表结构. NULL代表没有实例变量.不包括父类的变量. */
  struct objc_method_list*  methods;    /* 链接类中定义的实例方法. */
  struct sarray *    dtable;            /* 指向实例方法分配表. */ 
  struct objc_class* subclass_list;     /* 父类列表 */
  struct objc_class* sibling_class;
  struct objc_protocol_list *protocols; /* 要实现的原型列表 */
  void* gc_object_type;
};

Method(指针)

typedef struct objc_method *Method;

/* 编译器依据类中定义的方法为该类产生一个或更多这种这种结构.
*  一个类的实现可以分散在一个文件中不同部分,同时类别可以分散在不同的模块中.
*为了处理这个问题,使用一个单独的方法链表 
*/
struct objc_method
{
  SEL         method_name;  /* 这个变量就是方法的名称.编译器使用在这里使用一个`char*`,当一个方法被注册,名称在运行时被使用真正的SEL替代  */
  const char* method_types; /* 描述方法的参数列表. 在运行时注册选择器时使用.那时候方法名就会包含方法的参数列表.*/
  IMP         method_imp;   /* 方法执行时候的地址. */
};

Ivar(指针)

typedef struct objc_category *Category;

/* 编译器为每个类别产生一个这样的结构.一个类可以具有多个类别同时既包括实例方法,也可以包括类方法*/
struct objc_category
{
  const char*   category_name;                /* 类别名.定义在类别后面的括号内*/
  const char*   class_name;                   /* 类名 */
  struct objc_method_list  *instance_methods; /* 链接类中定义的实例方法. NULL表示没有实例方法. */
  struct objc_method_list *class_methods;     /* 链接类中定义的类方法. NULL表示没有类方法. */
  struct objc_protocol_list *protocols;       /* 遵循的协议表  */
};

objc_property_t

typedef struct objc_property *objc_property_t;

IMP

id (*IMP)(id, SEL, ...)

SEL

typedef struct objc_selector *SEL;

struct objc_selector
{
  void *sel_id;
  const char *sel_types;
};

objc_method_list

struct objc_method_list
{
  struct objc_method_list*  method_next; /* 这个变量用来链接另一个单独的方法链表 */
  int            method_count;            /* 结构中定义的方法数量 */
  struct objc_method method_list[1];      /* 可变长度的结构 */
};

objc_cache

struct objc_cache
{
    unsigned int mask;
    unsigned int occupied;
    Method buckets[1];
};

objc_protocol_list

struct objc_protocol_list
{
  struct objc_protocol_list *next;
  size_t count;
  struct objc_protocol *list[1];
};

Runtime 又叫运营时,是后生可畏套底层的 C 语言 API,其为 iOS
内部的宗旨之黄金年代,大家一贯编写制定的 OC
代码,底层都以依赖它来兑现的。比方方法调用:

Objective-C底层数据结构

实例的数据结构

id

typedef struct objc_object *id;

objc_object

struct objc_object
{
  /* 类的指针是对象相关的类.如果是一个类对象, 这个指针指向元类.
  Class isa;
};

objc_super

struct objc_super
{
  id    self;        /* 消息的接受者  */
  Class super_class; /* 接受者的父类  */
};

原稿地址:Objective-C底层数据结构

[objA  someMethod];本质上是objc_msgSend(objA,someMethod).

Objective-C底层数据结构

类的数据结构

我们常说Objective-C是动态语言,这实际上正是得益于Runtime。有了Runtime,大家得以在程序运行时拿到某些类的富有成员变量以至艺术列表,还足以动态拉长方法、方法交换等。

Class(指针)

typedef struct objc_class *Class;

/*
  这是由编译器为每个类产生的数据结构,这个结构定义了一个类.这个结构是通过编译器在执行时产生,在运行时发送消息时使用.因此,一些成员改变了类型.编译器产生"char* const"类型的字符串指针替代了下面的成员变量"super_class"
*/
struct objc_class {
  struct objc_class*  class_pointer;    /* 指向元类的指针. */
  struct objc_class*  super_class;      /* 指向父类的指针. 对于NSObject来说是NULL.*/
  const char*         name;             /* 类的名称. */
  long                version;          /* 未知. */
  unsigned long       info;             /* 比特蒙板.  参考下面类的蒙板定义. */
  long                instance_size;    /* 类的字节数.包含类的定义和所有父类的定义 */
#ifdef _WIN64
  long pad;
#endif
  struct objc_ivar_list* ivars;         /* 指向类中定义的实例变量的列表结构. NULL代表没有实例变量.不包括父类的变量. */
  struct objc_method_list*  methods;    /* 链接类中定义的实例方法. */
  struct sarray *    dtable;            /* 指向实例方法分配表. */ 
  struct objc_class* subclass_list;     /* 父类列表 */
  struct objc_class* sibling_class;
  struct objc_protocol_list *protocols; /* 要实现的原型列表 */
  void* gc_object_type;
};

要完美领悟OC的Runtime,必须领会以下术语:

Method(指针)

typedef struct objc_method *Method;

/* 编译器依据类中定义的方法为该类产生一个或更多这种这种结构.
    一个类的实现可以分散在一个文件中不同部分,同时类别可以分散在不同的模块中.为了处理这个问题,使用一个单独的方法链表 */
struct objc_method
{
  SEL         method_name;  /* 这个变量就是方法的名称.编译器使用在这里使用一个`char*`,当一个方法被注册,名称在运行时被使用真正的SEL替代  */
  const char* method_types; /* 描述方法的参数列表. 在运行时注册选择器时使用.那时候方法名就会包含方法的参数列表.*/
  IMP         method_imp;   /* 方法执行时候的地址. */
};

SEL、IMP、id、Class、Method、Ivar.

Ivar(指针)

typedef struct objc_ivar *Ivar;

/* 编译器依据类中定义的实例变量为该类产生一个或更多这种这种结构  */
struct objc_ivar
{
  const char* ivar_name;  /* 类中定义的变量名. */
  const char* ivar_type;  /* 描述变量的类型.调试时非常有用. */
  int        ivar_offset; /* 实例结构的基地址偏移字节 */
};

SEL

Category(指针)

typedef struct objc_category *Category;

/* 编译器为每个类别产生一个这样的结构.一个类可以具有多个类别同时既包括实例方法,也可以包括类方法*/
struct objc_category
{
  const char*   category_name;                /* 类别名.定义在类别后面的括号内*/
  const char*   class_name;                   /* 类名 */
  struct objc_method_list  *instance_methods; /* 链接类中定义的实例方法. NULL表示没有实例方法. */
  struct objc_method_list *class_methods;     /* 链接类中定义的类方法. NULL表示没有类方法. */
  struct objc_protocol_list *protocols;       /* 遵循的协议表  */
};

正如上边所言,在OC此中办法调用实际上是发音讯,参数个中的someMethod正是二个SEL类型,是selector在Objc此中的象征,其数据结构是:

objc_property_t

typedef struct objc_property *objc_property_t;

typedef  struct objc_selector *SEL;

IMP

id (*IMP)(id, SEL, ...)

能够观看,它是一个针对 objc_selector
指针,表示方法的名字/具名(本质正是叁个字符串卡塔 尔(英语:State of Qatar)。所以,对于分歧类的的等同的selector,其SEL是大同小异的。

SEL

typedef struct objc_selector *SEL;

struct objc_selector
{
  void *sel_id;
  const char *sel_types;
};

IMP

objc_method_list

struct objc_method_list
{
  struct objc_method_list*  method_next; /* 这个变量用来链接另一个单独的方法链表 */
  int            method_count;            /* 结构中定义的方法数量 */
  struct objc_method method_list[1];      /* 可变长度的结构 */
};

实在,有了SEL仍然无法确实的号令方式调用,真正起效果的照旧其意气风发IMP。先看一下IMP的数据结构:

objc_cache

struct objc_cache
{
    unsigned int mask;
    unsigned int occupied;
    Method buckets[1];
};

IMP在objc.h中的定义是:typedef id(*IMP)(id, SEL, …);

objc_protocol_list

struct objc_protocol_list
{
  struct objc_protocol_list *next;
  size_t count;
  struct objc_protocol *list[1];
};

能够观察IMP实际上是生龙活虎函数指针,指向哪些地点吧?指向这么些IMP对应的函数代码在内部存款和储蓄器中的位置。从结构体能够看来,这一个中的率先个参数是id类型,代表要实施该措施的靶子;第三个参数,SEL就很好精通了,就是艺术的名字。

实例的数据结构

id

id

typedef struct objc_object *id;

这些术语在上头已经见到过,是指向有个别类的实例的指针,数据结构如下:

objc_object

struct objc_object
{
  /* 类的指针是对象相关的类.如果是一个类对象, 这个指针指向元类.
  Class isa;
};

typedef struct objc_object *id;

objc_super

struct objc_super
{
  id    self;        /* 消息的接受者  */
  Class super_class; /* 接受者的父类  */
};

← 上一篇

Objective-C底层数据结构
Objective-C底层数据结构 类的数据结构 Class(指针) typedef struct
objc_class *Class; /* 那是由编写翻译器为每…

struct objc_object { Class isa; };

以上定义,看见objc_object结构体包蕴多少个 isa 指针,依据 isa
指针就能够找到指标所属的类。

注意:

isa
指针在代码运转时并不总指向实例对象所属的品类,所以不能信赖它来显明项目,要想明确项目或然要求用对象的-class方法。KVO
的兑现机理正是将被考核对象的 isa 指针指向一个个中类并非忠实类型。

id类型是运营时的动态类型,编写翻译器无法知晓它的真实类型,纵然你发送三个id类型未有的法子,也不会生出编写翻译警示。在实质上支付进度中,大家日常钦赐完结某些代理的靶子为id类型:

id<xxxxxxDelegate>,那是因为我们并不知道由何人促成这几个代理,不掌握其品种,所以就用id类型。

Class

下边包车型大巴内容早就关系过Class了,先看一下它的数据结构:

typedef struct objc_class *Class;

Class其实是指向objc_class结构体的指针。这些结构体主要有以下定义:

Class super_class   那是指向父类的指针

constchar *name  类名

struct objc_ivar_list *ivars     分子变量列表

struct objc_method_list **methodLists   方法列表

struct objc_protocol_list *protocols   达成的商讨列表

要介怀两点:

1、objc_class中也会有叁个 isa 指针,那表达 Objc
类本身也是叁个对象。类对象所属的类就称为元类(Meta Class卡塔尔国,它
表述了类对象自己所怀有的元数据。

2、我们能够透过改过类的methodLists实未来运作时为类加多方法,那也是
Category
完结的准绳。但Category不是真正的类,并从未isa指针,Category只会把团结的method
attach到主类,并不会影响到主类的IvarList。那正是干什么分类里面不可能充实成员变量的原由。参照他事他说加以考查链接:Categry为何不能够增多属性

Method

Method 代表类中有个别方法的花色

typedef struct objc_method *Method;struct objc_method {

    SEL method_name                                 OBJC2_UNAVAILABLE;

    char *method_types                              
 OBJC2_UNAVAILABLE;    

     IMP method_imp                                  
 OBJC2_UNAVAILABLE;

}

介绍了IMP和SEL,这么些Method就很好精晓了。

Ivar

Ivar是代表成员变量的档次。

typedef struct objc_ivar *Ivar;struct objc_ivar {

char *ivar_name                                         
OBJC2_UNAVAILABLE;

char *ivar_type                                           
OBJC2_UNAVAILABLE;

int ivar_offset                                               
OBJC2_UNAVAILABLE;

}

其中ivar_offset是集散地址偏移字节

相关文章