C --> OC with RunTime
前言
本来打算写一篇关于runtime的学习总结,无奈长篇大论不是我的风格,就像写申论一样痛苦,加之网上关于tuntime的文章多如牛毛,应该也够童子们学习的了,今天就随便聊聊我的理解吧。
runtime是什么
对于初学者,runtime如尼斯湖水怪一样,只存在于传说中,对于开发者,runtime是做好iOS开发,或是深刻掌握Objective C所必需理解的东西。大公司面试都喜欢问:你对runtime熟悉吗?并不是runtime在开发中经常用到,我认为它是OC最核心的部分,只有掌握好它,你才能理解其底层的原理,而不是做一个只会造轮子的码农。要练成盖世神功,需先奠定自身深厚的内功,而tuntime就是iOS开发中的内功。
那么runtime到底是什么鬼?
runtime是一个c和汇编写的动态库(感谢Lision的指正),它就像一个小小的系统,将OC和C紧密关联,这个系统主要做两件事 :
1、封装C语言的结构体和函数,让开发者在运行时创建、检查或者修改类、对象和方法等等。
2、传递消息,找出方法的最终执行代码。
听起来蛮抽象的,我们来点通俗的吧?没问题~~
我们先写一句OC的代码
[zhangsan walkTheDog];
那么在运行时runtime会将它转化成C语言的代码
objc_msgSend(zhangsan, @selector(walkTheDog));
这个方法就是发送消息的方法,类似这样的方法runtime提供了很多,比如:
objc_property_t * class_copyPropertyList ( Class cls, unsigned int *outCount ); // 获取属性列表
Method * class_copyMethodList ( Class cls, unsigned int *outCount ); // 获取所有方法的数组
BOOL class_addMethod ( Class cls, SEL name, IMP imp, const char *types ); // 添加方法
那么我们可以利用这些方法干点什么?
1、遍历对象的属性
比如,看看zhangsan的有哪些属性(身高:180、年龄:18)
2、动态添加/修改属性,动态添加/修改/替换方法
比如,修改zhangsan的身高为190、年龄为20,替换walkTheDog方法(变成walkTheBigDog),给他添加一个新方法(walkTheCat)等等
3、动态创建类/对象/协议等等
比如,创建一个新的对象:lisi
4、方法拦截调用
比如,给zhangsan发送一个walkTheDog消息,但是zhangsan不知道怎么walk啊(没实现该方法),那我们可以拦截下,给该方法动态添加一个实现,甚至可以讲该方法定向或者打包给lisi(其他对象),让lisi来walk。
以上就是runtime的通俗解释,只是稍微举个例子,更多用法大家可以发挥聪明才智,举一反三。
方法调用流程
通俗地讲,调用方法(包含实例方法和类方法)相当于給一个对象发送消息。
所以,实际上,类本身也是一个对象(关于Class这一块就不再这里展开了)。
当我们调用一个方法时,是这样的:
Instance:调用实例方法时,会到对象所属的类的方法列表中查找。
Class:调用类方法时,会到类的metaClass的方法列表中查找。
下面以实例对象调用方法[blackDog walk]
为例描述方法调用的流程:
1、编译器会把`[blackDog walk]`转化为`objc_msgSend(blackDog,SEL)`,SEL为@selector(walk)。
2、Runtime会在blackDog对象所对应的Dog类的方法缓存列表里查找方法的SEL
3、如果没有找到,则在Dog类的方法分发表查找方法的SEL。(类由对象isa指针指向,方法分发表即methodList)
4、如果没有找到,则在其父类(设Dog类的父类为Animal类)的方法分发表里查找方法的SEL(父类由类的superClass指向)
5、如果没有找到,则沿继承体系继续下去,最终到达NSObject类。
6、如果在234的其中一步中找到,则定位了方法实现的入口,执行具体实现
7、如果最后还是没有找到,会面临两种情况:
``(1) 如果是使用`[blackDog walk]`的方式调用方法``
``(2) 使用`[blackDog performSelector:@selector(walk)]`的方式调用方法``
第一种情况编译器会报错,第二种需要到运行时才能确定对象能否接收指定的消息,这时候会进入消息转发的流程:
消息转发流程
1、动态方法解析
接收到未知消息时(假设blackDog的walk方法尚未实现),runtime会调用+resolveInstanceMethod:(实例方法)
或者+resolveClassMethod:(类方法)
在该方法中,我们可以給未知消息新增一个已经实现了的方法。
void walkFunc(id self, SEL _cmd) {
//let the dog walk
}
+ (BOOL)resolveInstanceMethod:(SEL)sel {
NSString * selString = NSStringFromSelector(sel);
if ([selString isEqualToString:@"walk"]) {
class_addMethod(self.class, @selector(walk), (IMP)walkFunc, "@:");
}
return [super resolveInstanceMethod:sel];
}
2、备用接收者
如果以上方法没有做处理,runtime会调用- (id)forwardingTargetForSelector:(SEL)aSelector
方法。
如果该方法返回了一个非nil(也不能是self)的对象,而且该对象实现了这个方法,那么这个对象就成了消息的接收者,消息就被分发到该对象。
适用情况:通常在对象内部使用,让内部的另外一个对象处理消息,在外面看起来就像是该对象处理了消息。
比如:blackDog让女朋友whiteDog来接收这个消息
- (id)forwardingTargetForSelector:(SEL)aSelector {
NSString * selString = NSStringFromSelector(aSelector);
if ([selString isEqualToString:@"walk"]) {
return self.whiteDog;
}
return [super forwardingTargetForSelector:aSelector];
}
3、完整消息转发
在- (void)forwardInvocation:(NSInvocation *)anInvocation
方法中选择转发消息的对象,其中anInvocation对象封装了未知消息的所有细节,并保留调用结果发送到原始调用者。
比如:blackDog将消息完整转发給主人dogOwner来处理
- (void)forwardInvocation:(NSInvocation *)anInvocation {
if ([DogOwner instancesRespondToSelector:anInvocation.selector]) {
[anInvocation invokeWithTarget:self.dogOwner];
}
}
4、如果在以上三个方法都没有处理未知消息,则会引发异常。
后记
本文主要通俗地描述了runtime的概念,并对其主要作用做了简单的概括,旨在給读者抛砖引玉,runtime的奥妙之处就由读者多多探索学习了。
初学者需要更深入地学习:
1、基本概念:Class、Ivar、Method等等
2、消息转发机制
3、在<objc/runtime.h>中理解runtime提供的方法和功能
4、在实际开发中如何灵活运用runtime
^_^相对于理论,程序员总是更擅长用代码来表达,博主接下来将陆续更新runtime实战应用系列文章,敬请关注。
1.http://www.jianshu.com/p/f493bc6a949e/comments/1688988#comment-1688988
2.http://www.jianshu.com/p/d361f169423b
C --> OC with RunTime的更多相关文章
- OC中Runtime浅析
近期了解了一下OC的Runtime,真的是OC中非常强大的一个机制,看起来比較底层,但事实上能够有非常多活用的方式. 什么是Runtime 我们尽管是用Objective-C写的代码,事实上在运行过程 ...
- OC的runtime运行机制
什么是runtime runtime就是一套底层的c语言API(Application Programming Interface)里面包括很多强大实用的c语言类型.c语言函数. 实际上,平时我们编写 ...
- iOS开发——高级技术精选OC篇&Runtime之字典转模型实战
Runtime之字典转模型实战 如果您还不知道什么是runtime,那么请先看看这几篇文章: http://www.cnblogs.com/iCocos/p/4734687.html http://w ...
- OC中runtime的使用
一.runtime简介* RunTime简称运行时.OC就是“运行时机制”,也就是在运行时候的一些机制,其中最主要的是消息机制.* 对于C语言,“函数的调用在编译的时候会决定调用哪个函数”.* 对于O ...
- 什么是动态语言 OC 的runtime
OC是一门 动态语言. 问题来了.什么是动态语言? 与之相对的静态语言? 学习C++的时候,记得一个名词:“运行时的动态绑定”. 这个是 “多态”的概念. 简单提一下:关键:类指针可以指向本类,或者其 ...
- OC语言-runtime
参考博客 IOS高级开发-Runtime(一) http://blog.csdn.net/lizhongfu2013/article/details/9496705 apple官方参考 Object- ...
- oc - runtime运行机制
Objective-C语言是一门动态语言,它将很多静态语言在编译和链接时做的事放到了运行时来处理.同时OC也是一门简单的语言,很大一部分是C的内容,只是在语言层面上加了关键字和语法,真正让OC强大 ...
- iOS runtime探究(二): 从runtime開始深入理解OC消息转发机制
你要知道的runtime都在这里 转载请注明出处 http://blog.csdn.net/u014205968/article/details/67639289 本文主要解说runtime相关知识, ...
- 18 (OC)* RunTime
目录: 一.怎么理解OC是动态语言,Runtime又是什么?二.理解消息机制的基本原理三.与Runtime交互的三种方式四.分析Runtime中的数据结构五.深入理解Rutime消息发送原理六.多继承 ...
随机推荐
- JVM基础01-内存分配
一.什么是JVM Java作为主流编程语言: 它摆脱了硬件的束缚,一处编写,处处运行: 它提供了一种相对安全的内存管理和访问机制,避免了大部分的内存泄露和指针越界问题: 它实现了热点代码的检测和运行时 ...
- 关于oracle数据库(9)
内连接:从多张表中获取综合数据 inner join on select 表1.字段,表2.字段 from 表1 inner join 表2 on 关系; select 表1.*,表2.* from ...
- 移动前端不得不了解的HTML5 head 头标签(首篇)
HTML的头部内容特别多,有针对SEO的头部信息,也有针对移动设备的头部信息.而且各个浏览器内核以及各个国内浏览器厂商都有些自己的标签元素,有很多差异性.移动端的工作已经越来越成为前端工作的重要内容, ...
- VBS虚拟键码
1 VK_LBUTTON 鼠标左键 2 VK_RBUTTON 鼠标右键 3 VK_CANCEL Ctrl+Break(通常不需要处理) 4 VK_MBUTTON 鼠标中键 8 VK_BACK Back ...
- MFC中为菜单或按钮添加快捷键功能
1.新建一快捷键资源,ACCELERATOR,关联相应的ID号,下图所示中,其中,第一个ID为自定义快捷键ID,按CTRL+R,此时响应该ID以应的消息响应函数, 第二个ID为菜单ID,此时按CTRL ...
- php curl 获取 HTTPS
注意:谷歌的话开vpn可能才可以,goagent也不行function getHTTPS($url) { $ch = curl_init(); curl_setopt($ch, CURLOPT_S ...
- hdu_5775_Bubble Sort(树状数组)
题目链接:hdu_5775_Bubble Sort 题意: 让你找每一个数在冒泡排序中最右边和最左边的位置的差值 题解: 还是官方题解,讲的已经很清楚了 1012 Bubble Sort 考虑一个位置 ...
- hdu_3555_Bomb(数位DP)
题目连接:hdu_3555_Bomb 题意:和2089一样,只是数据大了点,不过道理是一样的 #include<cstdio> #include<cstring> #defin ...
- The 3n + 1 problem
The 3n + 1 problem Time Limit : 2000/1000ms (Java/Other) Memory Limit : 65536/32768K (Java/Other) ...
- ios 中NSArray
// #import <Foundation/Foundation.h> #import "Animal.h" int main(int argc, const cha ...