RunTime基本概念之SEL,Class,id,IMP,_cmd,isa,method,Ivar

RunTime使用还是比较多的,但是有一些基本的概念问题还是很容易混淆,所以在此处做一个记录,针对自己不是很好理解的地方做了详细记录。黄文臣大神的博客写的特别好,先收录一下,转载链接在文末。这么棒的博客也推荐给大家一下,希望能够跟随大神的脚步共同进步!

概念表

概念表.png

注意,虚线标识isa指针,实线表示父类。
下图简要分析:
主要列举出来子类、父类以及基类的指针指向及其相互之间的联系,实例方法列表最终指向了元类。

类isa的传递

从图中我们可以看出,所有实例对象的isa都指向它所属的类,而类的isa指针指向它的元类。所有元类的isa指针指向它的基类的meta-class(元类),基类的meta-class的isa指针指向自己。需要注意的是,root-class(基类)的superclass是nil。
meta-class(元类)存储着一个类的所有类方法,注意是所有类方法噢。
1、向一个对象发送消息时,runtime会在这个对象所属的类的方法列表中查找方法,是实例方法;
2、向一个类发送消息时,会在这个类的meta-class(元类)的方法列表中查找;

Rumtime实际开发中用到的比较多的场景:

  • 动态改变方法的执行体
  • Method Swizzling
  • NSSelectorFromString,NSClassFromString…
  • 动态添加属性(主要是类别)
  • 动态遍历属性和方法,动态为类添加方法

什么是Runtime?

Objective C语言把能在运行期做的事情就推迟到运行期再决定。这就意味着,Objective C不仅需要一个编译器,而且需要一个运行期环境。这个运行期环境就是Runtime。

最直接的例子就是方法调用
这样的一个OC方法

[receiver message]

会被编译成

objc_msgSend(receiver, selector)

这里,先记着receiver就是接受消息的对象,selector是执行消息的函数体名称,是个C的字符串。而不是像其他语言一样,直接编译成一个指向函数体的指针。

那么,在运行的时候,如何通过objc_msgSend(receiver, selector)找到实际的函数体呢?

That is Runtime!


为什么要写这样一篇基础的文章?

记得最开始接触Runtime的时候,感觉很乱,看得我最后都迷糊了,最后想了想,主要还是一些基本概念不清楚,搞不清楚这些名词是几乎不可能深入理解和应用Runtime的。

所以,我讲解Runtime的方式是,先搞清楚一些基本的关键词的底层定义,然后讲解消息处理以及转发机制,最后讲解示例。


SEL/objc_selector

objc_selector

透明的数据结构,可以理解为C String,为运行时方法的名称。

SEL
源代码定义

typedef struct objc_selector *SEL;

也就是说,SEL是指向一个C String的指针,也就是指向方法的指针。


id/objc_object

id - 指向一个类的实例对象
底层代码定义

typedef struct objc_object *id;

其中
objc_object的底层定义

struct objc_object {
    Class isa  OBJC_ISA_AVAILABILITY;
};

可以看到,objc_object中,只是保存了一个Class类型的isa。这里看不懂不要怕,先记着,对象中就是保存了一个指向Objective C中对应类的指针。


Class/objc_class

Class - 指向Objective C类对象(objc_class)的一个指针
底层定义如下图所示:


objc_class定义.png

可以看到,这就是类对象结构体的定义,细心的同学可能发现了类对象里仍然有一个指针Class isa,先记着,这个isa指向的是类元对象。

  • 这里我们强调介绍下Cache:
    Cache用于缓存最近使用的方法。一个类只有一部分方法是常用,每次调用一个方法之后,这个方法就会被缓存到Cache中,下次调用方法时runtime会先在Cache中查找方法,如果没有才会到methodList中查找方法。有了Cache,经常用到的方法的调用效率就高多了。
    其实,runtime就是一个库,它是一套API,这个库使C语言有了面向对象的能力。我们可以使用runtime这个库里面的各种方法,在运行的时候对类、实例对象、变量、属性、方法等进行各种操作。

类元(meat-class)对象

meta-class (类元)存储着一个类的所有类方法。
1、向一个对象发送消息时,runtime会在这个对象所属的类的方法列表中查找方法。
2、向一个类发送消息时,runtime会在这个类的meta-class(类元)的方法列表中查找。
3、meta-class是一个类,也可以向它发送消息,那么他的isa又指向什么呢?为了让这种结构无限延伸下去,OC设计者让所有的meta-class的isa指向基类(NSObject)的meta-class,而基类的meta-class指针指向自己。


IMP

IMP-指向实际执行函数体的函数指针

#if !OBJC_OLD_DISPATCH_PROTOTYPES
typedef void (*IMP)(void /* id, SEL, ... */ ); 
#else
typedef id (*IMP)(id, SEL, ...); 
#endif

可以看到,这个函数体前两个参数是 id(消息接受者,也就是对象),以及SEL(方法的名字)


method/objc_method

Method是用于表示类的方法,Method结构体中包含一个SEL和IMP,SEL方法名,IMP方法的实现。
method - 指向Objective C中的方法的指针

typedef struct objc_method *Method;

其中

struct objc_method {
    SEL method_name                                          OBJC2_UNAVAILABLE;
    char *method_types                                       OBJC2_UNAVAILABLE;
    IMP method_imp                                           OBJC2_UNAVAILABLE;
}                                                            OBJC2_UNAVAILABLE;


_cmd

SEL 类型的一个变量,Objective C的函数的前两个隐藏参数为self 和 _cmd

functionForMethod(id self, SEL _cmd){
NSLog(@"%@-----%p",self,_cmd);
}

Ivar

ivar - objective C中的实例变量

typedef struct objc_ivar *Ivar;

可以看到变量的内存模型

struct objc_ivar {
    char *ivar_name                                          OBJC2_UNAVAILABLE;
    char *ivar_type                                          OBJC2_UNAVAILABLE;
    int ivar_offset                                          OBJC2_UNAVAILABLE;
#ifdef __LP64__
    int space                                                OBJC2_UNAVAILABLE;
#endif
}                                                            OBJC2_UNAVAILABLE;

有太多优秀的人值的学习,做人还是要有追求的,不然生命力也会一点点的流失,最终难免死气沉沉。个人认为不管什么事,管它有多难,自己不认输就不会输!如果说我对自己有什么期望的话,我希望自己能更坚韧成熟一些,能活的更精彩一些,能够不辜负自己。向前吧!

参考文章地址:
http://blog.csdn.net/hello_hwc?viewmode=list
https://blog.csdn.net/hello_hwc/article/details/49687543
https://www.2cto.com/kf/201708/668790.html
runtime的使用

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

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,241评论 25 707
  • 笑来老师说,要把智慧用到大事上,然而生活中我们常常见到一些有小聪明的人,算盘扒拉的哗哗响,自己一点亏都不能吃,斤斤...
    遇见橙子阅读 163评论 0 0
  • 不经历失去,怎么会反思,怎会成长。 有些人失去过后,便是怀疑,是堕落。 有些人失去过后,是反思,是经历,更是成长。...
    小千世界O阅读 167评论 0 0
  • 想把英文学好?嘘!什么都不要说,先把你的手机调成英文模式吧。 请问你调了吗?没有。没有还不赶紧调。 如果我问大家一...
    暖暖先森阅读 1,657评论 15 14
  • 如果你是标题党,看到我的标题进来的,那就欢迎光临。 嗯,我是一名大二的学生,大一刚开学的时候,很闲,就是很想找点事...
    安刈阅读 404评论 5 4