iOS开发基础性知识(十二)----iOS底层数据结构

一、类的数据结构

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_ivar *Ivar;

/* 编译器依据类中定义的实例变量为该类产生一个或更多这种这种结构  */

struct objc_ivar

{

const char* ivar_name;  /* 类中定义的变量名. */

const char* ivar_type;  /* 描述变量的类型.调试时非常有用. */

int        ivar_offset; /* 实例结构的基地址偏移字节 */

};

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;      /* 遵循的协议表  */

};

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];

};

二、实例的数据结构

id

typedef struct objc_object *id;

objc_object

struct objc_object

{

// 类的指针是对象相关的类.如果是一个类对象, 这个指针指向元类.

Class isa;

};

objc_super

struct objc_super

{

id    self;        /* 消息的接受者  */

Class super_class; /* 接受者的父类  */

};

三、底层-Class详解(iOS)

• iOS的开发语言objective-c,它的真实面目是它不是真正的面向对象语言,而抽象理解为此而已。其实它就是C+,有个公式可以很好地诠释那就是OC = C + Runtime;

• 接下来我们就好好讲讲在Runtime下的objc-class。

3.1Class定义

3.1.1 小小说明一下objc-api.h里的OBJC_ISA_AVAILABILITY:

• /*介绍一下attribute((deprecated))的作用,__attribute是给函数、变量、类做属性说明的关键字,deprecated是弃用原先的进行兼容

• 若是OBJC2,原先的类,编译器发出警告*/

#if !defined(OBJC_ISA_AVAILABILITY)

#  if __OBJC2__

#      define OBJC_ISA_AVAILABILITY  __attribute__((deprecated))

#  else

#      define OBJC_ISA_AVAILABILITY  /* still available */

#  endif

#endif

typedef struct objc_method *Method;

typedef struct objc_ivar *Ivar;

typedef struct objc_category *Category;

typedef struct objc_property *objc_property_t;

3.1.2 接下来就是runtime.h里的Class的定义:

struct objc_class {

Class isa  OBJC_ISA_AVAILABILITY;//每个Class都有一个isa指针

#if !__OBJC2__

Class super_class                                        OBJC2_UNAVAILABLE;//父类

const char *name                                        OBJC2_UNAVAILABLE;//类名

long version                                            OBJC2_UNAVAILABLE;//类版本

long info                                                OBJC2_UNAVAILABLE;//!*!供运行期使用的一些位标识。如:CLS_CLASS (0x1L)表示该类为普通class; CLS_META(0x2L)表示该类为metaclass等(runtime.h中有详细列出)

long instance_size                                      OBJC2_UNAVAILABLE;//实例大小

struct objc_ivar_list *ivars                            OBJC2_UNAVAILABLE;//存储每个实例变量的内存地址

struct objc_method_list **methodLists                    OBJC2_UNAVAILABLE;//!*!根据info的信息确定是类还是实例,运行什么函数方法等

struct objc_cache *cache                                OBJC2_UNAVAILABLE;//缓存

struct objc_protocol_list *protocols                    OBJC2_UNAVAILABLE;//协议

#endif

} OBJC2_UNAVAILABLE;

四、class初始化

• Runtime的行为之一就是initialize。在程序运行过程中,它会在你程序中每个类调用一次initialize。这个调用的时间发生在你的类接收到消息之前,但是在它的超类接收到initialize之后。

//在苹果的官方Runtime中有个objc-initialize.m文件,进行解读

typedef struct _objc_initializing_classes {

int classesAllocated;//类是否分配存在

Class *metaclasses;//类的父类,如果没有父类那就是自身

}

_objc_initializing_classes;//初始化一个对象_objc_initializing_classes

//将所有的类存储在静态链表中,以待接下来的接收和发送消息

static _objc_initializing_classes *_fetchInitializingClassList(BOOL create)

{

_objc_pthread_data *data;

//list为类链表

_objc_initializing_classes *list;

Class *classes;

data = _objc_fetch_pthread_data(create);

if (data == nil) return nil;

//链表增加类节点

list = data->initializingClasses;

if (list == nil) {

if (!create) {

return nil;

} else {

list = (_objc_initializing_classes *)

_calloc_internal(1, sizeof(_objc_initializing_classes));

data->initializingClasses = list;

}}//将创建的classes接在metaclasses后

classes = list->metaclasses;

if (classes == nil) {

// If _objc_initializing_classes exists, allocate metaclass array,

// even if create == NO.

// Allow 4 simultaneous class inits on this thread before realloc.

list->classesAllocated = 4;

classes = (Class *)

_calloc_internal(list->classesAllocated, sizeof(Class));

list->metaclasses = classes;

}return list;

}

五、runtime下Class的各项操作(重要几个)

5.1 add*(增加)

5.1.1 static IMP addMethod(Class cls, SEL name, IMP imp, const char *types, BOOL replace);//增加方法

5.1.2 BOOL class_addMethod(Class cls, SEL name, IMP imp, const char *types);//增加类方法

5.1.3 BOOL class_addIvar(Class cls, const char *name, size_t size,uint8_t alignment, const char *type);//增加实例变量

5.1.4 static BOOL _class_addProperty(Class cls, const char *name,const objc_property_attribute_t *attrs, unsigned int count,BOOL replace);//增加属性

5.2 replace*(修改)

5.2.1 IMP class_replaceMethod(Class cls, SEL name, IMP imp, const char *types); //修改方法

5.2.2 void class_replaceProperty(Class cls, const char *name,const objc_property_attribute_t *attrs, unsigned int n);//修改属性

5.3 get*(获取)

5.3.1 static Class getClass(const char *name);//获取类

5.3.2 static ivar_t *getIvar(Class cls, const char *name);//获取类变量(static相当于“+“)

5.3.3 Method class_getInstanceMethod(Class cls, SEL sel);//获取实例方法

5.3.4 static Method _class_getMethod(Class cls, SEL sel);;//获取类方法

5.3.5 static Protocol *getProtocol(const char *name);//增加协议

5.4 set*(设置)

5.4.1 objc_class::setInitialized();//set的initialized初始化

5.4.2 static Class setSuperclass(Class cls, Class newSuper);//设置父类

5.5 其他还有类似于 void *objc_destructInstance(id obj);//摧毁实例对象等等

六、Class的重要函数

6.1 get*(获取)

6.1.1 object_getClass(id obj);

6.1.2 IMP object_getMethodImplementation(id obj, SEL name);//获得实例方法实现

6.1.3 Ivar object_getInstanceVariable(id obj, const char *name, void **value)//获取实例属性

6.2 set*(设置)

6.2.1 Class object_setClass(id obj, Class cls);

6.2.2 Ivar object_setInstanceVariable(id obj, const char *name, void *value);//设置实例属性

6.2.3 void object_setIvar(id obj, Ivar ivar, id value);//设置实例变量

6.3 其他

6.3.1 static void _class_resolveClassMethod(Class cls, SEL sel, id inst);//动态添加类方法,不必在乎方法是否存在

6.3.2 static void _class_resolveInstanceMethod(Class cls, SEL sel, id inst);//动态添加实现方法,不必在乎方法是否存在

6.3.3 unsigned _class_createInstancesFromZone(Class cls, size_t extraBytes, void *zone,id *results, unsigned num_requested);//创建实例存储空间

6.4 消息转发

6.4.1 void    instrumentObjcMessageSends(BOOL flag);//flag传入YES,运行时发送的所有消息都会打印到/tmp/msgSend-xxxx文件里了。



站在巨人的肩膀上才有这些总结

菜鸟走向大牛,大家共同前进,如果觉得不错,请给个赞/关注。

一起交流学习,有问题随时欢迎联系,邮箱:383708669@qq.com

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,491评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,856评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,745评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,196评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,073评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,112评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,531评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,215评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,485评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,578评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,356评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,215评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,583评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,898评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,174评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,497评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,697评论 2 335

推荐阅读更多精彩内容

  • 转至元数据结尾创建: 董潇伟,最新修改于: 十二月 23, 2016 转至元数据起始第一章:isa和Class一....
    40c0490e5268阅读 1,670评论 0 9
  • 我们常常会听说 Objective-C 是一门动态语言,那么这个「动态」表现在哪呢?我想最主要的表现就是 Obje...
    Ethan_Struggle阅读 2,161评论 0 7
  • //联系人:石虎QQ: 1224614774昵称:嗡嘛呢叭咪哄 objc_class结构体 一、类在OC中是obj...
    石虎132阅读 2,173评论 0 21
  • Objective-C语言是一门动态语言,它将很多静态语言在编译和链接时期做的事放到了运行时来处理。这种动态语言的...
    有一种再见叫青春阅读 570评论 0 3
  • 原文出处:南峰子的技术博客 Objective-C语言是一门动态语言,它将很多静态语言在编译和链接时期做的事放到了...
    _烩面_阅读 1,211评论 1 5