[转载]Runtime详解
- Runtime介绍
- Runtime消息传递
- Runtime消息转发
- Runtime应用
Runtime介绍
Objective-C 扩展了 C 语言,并加入了面向对象特性和 Smalltalk 式的消息传递机制。而这个扩展的核心是一个用 C 和 编译语言 写的 Runtime 库。它是 Objective-C 面向对象和动态机制的基石。
Objective-C 是一个动态语言,这意味着它不仅需要一个编译器,也需要一个运行时系统来动态得创建类和对象、进行消息传递和转发。理解 Objective-C 的 Runtime 机制可以帮我们更好的了解这个语言,适当的时候还能对语言进行扩展,从系统层面解决项目中的一些设计或技术问题。了解 Runtime ,要先了解它的核心 - 消息传递 (Messaging)。
Runtime消息传递
- 首先,通过obj的isa指针找到它的 class ;
- 在 class 的 method list 找 foo ;
- 如果 class 中没到 foo,继续往它的 superclass 中找 ;
- 一旦找到 foo 这个函数,就去执行它的实现IMP 。
- //类
- struct objc_class {
- Class _Nonnull isa OBJC_ISA_AVAILABILITY;
- #if !__OBJC2__
- Class _Nullable super_class OBJC2_UNAVAILABLE;
- const char * _Nonnull name OBJC2_UNAVAILABLE;
- long version OBJC2_UNAVAILABLE;
- long info OBJC2_UNAVAILABLE;
- long instance_size OBJC2_UNAVAILABLE;
- struct objc_ivar_list * _Nullable ivars OBJC2_UNAVAILABLE;
- struct objc_method_list * _Nullable * _Nullable methodLists OBJC2_UNAVAILABLE;
- struct objc_cache * _Nonnull cache OBJC2_UNAVAILABLE;
- struct objc_protocol_list * _Nullable protocols OBJC2_UNAVAILABLE;
- #endif
- } OBJC2_UNAVAILABLE;
- 系统首先找到消息的接收对象,然后通过对象的isa找到它的类。
- 在它的类中查找method_list,是否有selector方法。
- 没有则查找父类的method_list。
- 找到对应的method,执行它的IMP。
- 转发IMP的return值。
- 类对象(objc_class)
- 实例(objc_object)
- 元类(Meta Class)
- Method(objc_method)
- SEL(objc_selector)
- IMP
- 类缓存(objc_cache)
- Category(objc_category)
类对象(objc_class)
- struct objc_class {
- Class _Nonnull isa OBJC_ISA_AVAILABILITY;
- #if !__OBJC2__
- Class _Nullable super_class OBJC2_UNAVAILABLE;
- const char * _Nonnull name OBJC2_UNAVAILABLE;
- long version OBJC2_UNAVAILABLE;
- long info OBJC2_UNAVAILABLE;
- long instance_size OBJC2_UNAVAILABLE;
- struct objc_ivar_list * _Nullable ivars OBJC2_UNAVAILABLE;
- struct objc_method_list * _Nullable * _Nullable methodLists OBJC2_UNAVAILABLE;
- struct objc_cache * _Nonnull cache OBJC2_UNAVAILABLE;
- struct objc_protocol_list * _Nullable protocols OBJC2_UNAVAILABLE;
- #endif
- } OBJC2_UNAVAILABLE;
struct objc_class结构体定义了很多变量,通过命名不难发现,
实例(objc_object)
- /// Represents an instance of a class.
- struct objc_object {
- Class isa OBJC_ISA_AVAILABILITY;
- };
- /// A pointer to an instance of a class.
- typedef struct objc_object *id;
类对象中的元数据存储的都是如何创建一个实例的相关信息,那么类对象和类方法应该从哪里创建呢?
就是从isa指针指向的结构体创建,类对象的isa指针指向的我们称之为元类(metaclass),
元类(Meta Class)
通过上图我们可以看出整个体系构成了一个自闭环,struct objc_object结构体实例它的isa指针指向类对象,
元类(Meta Class)是一个类对象的类。
Method(objc_method)
- struct objc_method {
- SEL _Nonnull method_name OBJC2_UNAVAILABLE;
- char * _Nullable method_types OBJC2_UNAVAILABLE;
- IMP _Nonnull method_imp OBJC2_UNAVAILABLE;
- } OBJC2_UNAVAILABLE;
Method和我们平时理解的函数是一致的,就是表示能够独立完成一个功能的一段代码,比如:这段代码,就是一个函数。
- SEL method_name 方法名
- char *method_types 方法类型
- IMP method_imp 方法实现
SEL(objc_selector)
- Objc.h
- /// An opaque type that represents a method selector.代表一个方法的不透明类型
- typedef struct objc_selector *SEL;
objc_msgSend函数第二个参数类型为SEL,它是selector在Objective-C中的表示类型(Swift中是Selector类)。selector是方法选择器,可以理解为区分方法的 ID,而这个 ID 的数据结构是SEL:
- 同一个类,selector不能重复
- 不同的类,selector可以重复
IMP
- /// A pointer to the function of a method implementation. 指向一个方法实现的指针
- typedef id (*IMP)(id, SEL, ...);
- #endif
就是指向最终实现程序的内存地址的指针。
类缓存(objc_cache)
Category(objc_category)
- name:是指 class_name 而不是 category_name。
- cls:要扩展的类对象,编译期间是不会定义的,而是在Runtime阶段通过name对 应到对应的类对象。
- instanceMethods:category中所有给类添加的实例方法的列表。
- classMethods:category中所有添加的类方法的列表。
- protocols:category实现的所有协议的列表。
- instanceProperties:表示Category里所有的properties,这就是我们可以通过objc_setAssociatedObject和objc_getAssociatedObject增加实例变量的原因,不过这个和一般的实例变量是不一样的。
从上面的category_t的结构体中可以看出,分类中可以添加实例方法,类方法,甚至可以实现协议,添加属性,不可以添加成员变量。
Runtime消息转发
- 动态方法解析
- 备用接收者
- 完整消息转发
动态方法解析
- - (void)viewDidLoad {
- [super viewDidLoad];
- // Do any additional setup after loading the view, typically from a nib.
- //执行foo函数
- [self performSelector:@selector(foo:)];
- }
- + (BOOL)resolveInstanceMethod:(SEL)sel {
- if (sel == @selector(foo:)) {//如果是执行foo函数,就动态解析,指定新的IMP
- class_addMethod([self class], sel, (IMP)fooMethod, "v@:");
- return YES;
- }
- return [super resolveInstanceMethod:sel];
- }
- void fooMethod(id obj, SEL _cmd) {
- NSLog(@"Doing foo");//新的foo函数
- }
打印结果:2018-04-01 12:23:35.952670+0800 ocram[87546:23235469] Doing foo
备用接收者
- #import "ViewController.h"
- #import "objc/runtime.h"
- @interface Person: NSObject
- @end
- @implementation Person
- - (void)foo {
- NSLog(@"Doing foo");//Person的foo函数
- }
- @end
- @interface ViewController ()
- @end
- @implementation ViewController
- - (void)viewDidLoad {
- [super viewDidLoad];
- // Do any additional setup after loading the view, typically from a nib.
- //执行foo函数
- [self performSelector:@selector(foo)];
- }
- + (BOOL)resolveInstanceMethod:(SEL)sel {
- return YES;//返回YES,进入下一步转发
- }
- - (id)forwardingTargetForSelector:(SEL)aSelector {
- if (aSelector == @selector(foo)) {
- return [Person new];//返回Person对象,让Person对象接收这个消息
- }
- return [super forwardingTargetForSelector:aSelector];
- }
- @end
打印结果:2018-04-01 12:45:04.757929+0800 ocram[88023:23260346] Doing foo
完整消息转发
- #import "ViewController.h"
- #import "objc/runtime.h"
- @interface Person: NSObject
- @end
- @implementation Person
- - (void)foo {
- NSLog(@"Doing foo");//Person的foo函数
- }
- @end
- @interface ViewController ()
- @end
- @implementation ViewController
- - (void)viewDidLoad {
- [super viewDidLoad];
- // Do any additional setup after loading the view, typically from a nib.
- //执行foo函数
- [self performSelector:@selector(foo)];
- }
- + (BOOL)resolveInstanceMethod:(SEL)sel {
- return YES;//返回YES,进入下一步转发
- }
- - (id)forwardingTargetForSelector:(SEL)aSelector {
- return nil;//返回nil,进入下一步转发
- }
- - (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
- if ([NSStringFromSelector(aSelector) isEqualToString:@"foo"]) {
- return [NSMethodSignature signatureWithObjCTypes:"v@:"];//签名,进入forwardInvocation
- }
- return [super methodSignatureForSelector:aSelector];
- }
- - (void)forwardInvocation:(NSInvocation *)anInvocation {
- SEL sel = anInvocation.selector;
- Person *p = [Person new];
- if([p respondsToSelector:sel]) {
- [anInvocation invokeWithTarget:p];
- }
- else {
- [self doesNotRecognizeSelector:sel];
- }
- }
- @end
打印结果:2018-04-01 13:00:45.423385+0800 ocram[88353:23279961] Doing foo
链接:https://www.jianshu.com/p/6ebda3cd8052
來源:简书
[转载]Runtime详解的更多相关文章
- 李洪强iOS经典面试题156 - Runtime详解(面试必备)
李洪强iOS经典面试题156 - Runtime详解(面试必备) 一.runtime简介 RunTime简称运行时.OC就是运行时机制,也就是在运行时候的一些机制,其中最主要的是消息机制. 对于C ...
- iOS开发-Runtime详解
iOS开发-Runtime详解 简介 Runtime 又叫运行时,是一套底层的 C 语言 API,其为 iOS 内部的核心之一,我们平时编写的 OC 代码,底层都是基于它来实现的.比如: [recei ...
- [转载]Pytorch详解NLLLoss和CrossEntropyLoss
[转载]Pytorch详解NLLLoss和CrossEntropyLoss 来源:https://blog.csdn.net/qq_22210253/article/details/85229988 ...
- (转载)详解网络传输中的三张表,MAC地址表、ARP缓存表以及路由表
郑重声明:原文转载于http://dengqi.blog.51cto.com/5685776/1223132 向好文章致敬!!! 一:MAC地址表详解 说到MAC地址表,就不得不说一下交换机的工作原理 ...
- 转载+++++iptables详解+++++转载
转载:http://blog.chinaunix.net/uid-26495963-id-3279216.html 一.前言 防火墙,其实说白了讲,就是用于实现Linux下访问控制的功能的,它分为硬件 ...
- 【转载】详解CreateProcess调用内核创建进程的过程
原文:详解CreateProcess调用内核创建进程的过程 昨天同学接到了腾讯的电面,有一题问到了CreateProcess创建进程的具体实现过程,他答得不怎么好吧应该是, 为了以防万一,也为了深入学 ...
- [转载]python 详解re模块
原文地址:python 详解re模块作者:Rocky 正则表达式的元字符有. ^ $ * ? { [ ] | ( ) .表示任意字符 []用来匹配一个指定的字符类别,所谓的字符类别就是你想匹配的一个字 ...
- [ 转载 ] Http详解2
HTTP是一个属于应用层的面向对象的协议,由于其简捷.快速的方式,适用于分布式超媒体信息系统 | |目录 1引言 2一.HTTP协议详解之URL篇 3二.HTTP协议详解之请求篇 4三.HTTP协议详 ...
- (转载)详解7.0带来的新工具类:DiffUtil
[Android]详解7.0带来的新工具类:DiffUtil 标签: diffutil 2017-04-17 18:21 226人阅读 评论(0) 收藏 举报 分类: Android学习笔记(94) ...
随机推荐
- Large repunit factors (Project Euler 132)
题目大意: 求出 大数111111.....1 (1e9个1) 前40个质因子的和. 思路:可以把原来的数表示成$\frac{10^k - 1}{9}$ 其中$k=10^9$ 如果一个质数$p$ 满 ...
- zmq重点
The zmq_msg_send(3) method does not actually send the message to the socket connection(s). It queues ...
- rest-framework框架的基本组件分析
一.快速实例化 二.序列化 三.视图 四.身份认证,权限认证,频率限制 五.分页 六.响应器 七.路由 八.解释器
- windows 下XAMPP 使用Nginx替代apache作为服务器
说实话, 在windows下使用Nginx 着实有点不太方便, 但因项目需求, 又不想换系统(虽然可以搞个虚拟机玩), 只能用Nginx了 好了, 不多说了. 开始... 首先我用的是xampp包(A ...
- Android无线测试之—UiAutomator UiSelector API介绍之八
对象搜索—特殊属性.节点与资源ID 一.特殊属性定位对象相关API 返回值 API 描述 UiSelector checkableboolean val) 是否可选择,一般开关组件上具有checkab ...
- UTI 唯一类型标识
本文转载至 http://blog.csdn.net/zaitianaoxiang/article/details/6657231 applicationdocumentationtypessys ...
- libnids介
转自:http://blog.chinaunix.net/uid-22832715-id-2111578.html Libnids开发包介绍 Libnids是一个用于网络入侵检测开发的专业编程 ...
- angularjs 复选框 单选框
关于复选框,在做项目的时候,有一下几点心得 单选框 1.判断哪个单选框选中的情况 html代码 判断该复选框是否选中 $scope.agree.isChecked 判断这个值,如果等于1,代表 ...
- jQuery插件——1.编写规则
jQuery插件编写规则如下: 1.命名规则:jquery.[插件名称].js 2.所有对象方法都应当附加到jQuery.fn对象上:所有的全局方法都应当附加到jQuery对象上. 3.在插件内部,t ...
- Jquery来对form表单提交(mvc方案)
来自:http://www.cnblogs.com/lmfeng/archive/2011/06/18/2084325.html 我先说明一下,这是asp.net mvc 里面的用法, Jquery来 ...