初探runtime
1 简介
runtime,也叫它运行时系统。它是用c写的一套API,oc代码底层实现全都依赖它。我们说它是运行时,是相比编译,在程序编译完成之后,一些对象可通过runtime来干一些在编译时看似不可能的事。比如,动态添加一个属性,动态添加一个方法,交换两个方法之类的,还有很多能力。可以说,runtime是幕后黑手之一(没有贬义)。举个例子,让你来感受一下runtime。
首先,创建一个对象Test *a = [[Test alloc] init];然后调用它的方法run,如下图:

从代码中看,好像是对象a去调用方法run,不过这样理解也可以,我这里想说的是,在终端使用命令clang -rewrite-objc main.m生成main.cpp文件,里面有下列代码,如图:

我们可以看到[a run]转换成了objc_msgSend(a, sel_registerName("run"));也就是说,对象a调用方法run,实际上是runtime调用了一个方法,参数就是对象和方法名,如果方法需要参数,会跟在后面,可以自己去试试。那么我们可以这样理解,所有的对象调用方法,最终都被转换成了objc_msgSend(id, sel)。
2 几个概念
2.1 isa
在oc里面有一个叫isa的指针,它指向元类,元类的isa又会指向根元类,最终指向了NSObject的元类,这样形成一个环。所谓元类,就是类对象,例如类A,实例化出一个对象a,那么对象a的isa指针就是指向A,类A本身也是一个对象,叫类对象。如下图所示:

我们打开objc/runtime.h,可以看到class的定义:
struct objc_class {
Class isa OBJC_ISA_AVAILABILITY;
#if !__OBJC2__ Class super_class OBJC2_UNAVAILABLE; // 父类
const char *name OBJC2_UNAVAILABLE; // 类名
long version OBJC2_UNAVAILABLE; // 类的版本信息,默认为0
long info OBJC2_UNAVAILABLE; // 类信息,供运行期使用的一些位标识
long instance_size OBJC2_UNAVAILABLE; // 该类的实例变量大小
struct objc_ivar_list *ivars OBJC2_UNAVAILABLE; // 该类的成员变量链表
struct objc_method_list **methodLists OBJC2_UNAVAILABLE; // 方法定义的链表
struct objc_cache *cache OBJC2_UNAVAILABLE; // 方法缓存
struct objc_protocol_list *protocols OBJC2_UNAVAILABLE; // 协议链表
#endif } OBJC2_UNAVAILABLE;
从上述代码中可以看到class的本质,它是一个含有isa指针的结构体,里面有父类、类名、方法列表、成员变量列表等变量。也就是说通过runtime我们可以知道该对象拥有的方法列表和成员变量列表,runtime提供了相应的api,这里就不赘述了。
2.2 SEL(方法选择器)
sel是方法编号,不同于函数指针,它只能通过方法名找到该方法的指针。对象内部有一个方法列表,sel通过方法名可以找到方法列表中的方法,这也是对象内部不能有同名函数的原因。下面举几个例子:
(1)通过sel进行方法选择器
SEL sel = NULL;
switch (count) {
case :
sel = @selector(dismiss);
break;
case :
sel = @selector(start);
default:
sel = @selector(stop);
break;
}
(2)延迟加载某个方法
[self performSelector:@selector(dismiss) withObject:nil afterDelay:2.0];2秒钟之后调用方法dismiss。
2.3 IMP(函数指针)
如果你没有忘记曾经被c支配的恐惧的话,应该对函数指针这个概念印象深刻,IMP就是函数指针。你可以这样理解,你能找到某个函数的指针,那么拥有该函数的对象就可以直接去调用了,而不需要通过方法名去调用。但是函数指针也是需要通过方法名去获取的,这里可以把IMP和SEL结合起来,看看下面的例子。
(1)找到当前对象的方法log的函数指针后,直接调用。同时,也可以找其他对象内部的函数指针,然后直接调用:
IMP imp = [self methodForSelector:@selector(log)];
imp();
(2)交换方法。当viewcontroller的子类调用viewWillAppear:时会变成调用方法logViewWillAppear:从而达到交换方法的目的。
+ (void)load{
Method method1 = class_getInstanceMethod([self class], @selector(viewWillAppear:));
Method method2 = class_getInstanceMethod([self class], @selector(logViewWillAppear:));
method_exchangeImplementations(method1, method2);
}
- (void)logViewWillAppear:(BOOL)animated{
NSString *className = NSStringFromClass([self class]);
if ([className hasPrefix:@"LMF"]) {
NSLog(@"%@ will appear", className);
}
[self logViewWillAppear:animated];
}
2.4 Method
在上面提到了Method,这里我们来看看Method到底是什么。首先看看runtime.h文件中的定义:
struct objc_method {
SEL method_name
char *method_types
IMP method_imp
}
可以看出,它是一个结构体,包含SEL和IMP,实际上相当于在SEL和IMP之间作了一个映射。有了SEL,我们便可以找到对应的IMP,从而调用方法的实现代码。
以上是初次研究runtime的一些心得,还有如何使用runtime和runtime使用场景等模块会在后续文章中讲到。
初探runtime的更多相关文章
- 【原】iOS动态性(二):运行时runtime初探(强制获取并修改私有变量,强制增加及修改私有方法等)
OC是运行时语言,只有在程序运行时,才会去确定对象的类型,并调用类与对象相应的方法.利用runtime机制让我们可以在程序运行时动态修改类.对象中的所有属性.方法,就算是私有方法以及私有属性都是可以动 ...
- iOS动态性 运行时runtime初探(强制获取并修改私有变量,强制增加及修改私有方法等)
借助前辈的力量综合一下资料. OC是运行时语言,只有在程序运行时,才会去确定对象的类型,并调用类与对象相应的方法.利用runtime机制让我们可以在程序运行时动态修改类.对象中的所有属性.方法,就算是 ...
- Objective-C Runtime初探:self super
题目 上题目,已知A是爷爷,B是爸爸,C是孙子. @interface A : NSObject - (void)f; @end @interface B : A - (void)f; - (void ...
- Runtime 类初探
Runtime类 认识 Runtime类 在每一个JVM进程中都会存在一个Runtime类,这个类的主要功能是取得一些与运行时有关的环境属性或创建进程等操作. 在Runtime类定义的时候,它的构造方 ...
- 初探nodeJS
一.node概要 对nodeJS早有耳闻,但是一直迟迟没有对它下手,哈哈哈,今儿咱就来初探一下它. nodeJS是个啥东东? nodeJS,我的理解就是可以运行在后端的JavaScript. 为什么它 ...
- [转]初探Metasploit的自动攻击
1. 科普Metasploit 以前只是个Back Track操作系统(简称:BT) 下的攻击框架,自成继承了后攻击渗透模块,隐隐有成为攻击平台的趋势. 我们都戏称它为美少妇,很简单,msf. 它 ...
- Microsoft .NET Native Developer Preview 内部初探(1)
Microsoft .NET Native Developer Preview 内部初探(1) MS 前段时间发布了.NET Native Developer Preview,被广大人员赋予“C++的 ...
- WCF初探-2:手动实现WCF程序
1.前言 上一篇,我们通过VS自带的模板引擎自动生成了一个wcf程序,接下来我们将手动实现一个wcf程序.由于应用程序开发中一般都会涉及到大量的增删改查业务,所以这个程序将简单演示如何在wcf中构建简 ...
- WCF初探-10:WCF客户端调用服务
创建WCF 服务客户端应用程序需要执行下列步骤: 获取服务终结点的服务协定.绑定以及地址信息 使用该信息创建 WCF 客户端 调用操作 关闭该 WCF 客户端对象 WCF客户端调用服务存在以下特点: ...
随机推荐
- 【Android界面实现】Drawable Animation 使用介绍
转载请注明出处:http://blog.csdn.net/zhaokaiqiang1992 (眼下仅仅能用在View对象上的动画效果的实现有两种,一种就是上一篇的View Animat ...
- 基于FPGA的DDR3多端口读写存储管理系统设计
基于FPGA的DDR3多端口读写存储管理系统设计 文章出处:电子技术设计 发布时间: 2015/03/12 | 1747 次阅读 每天新产品 时刻新体验专业薄膜开关打样工厂,12小时加急出货 机载 ...
- [docker]bind9.11-with-mysql5.6 docker容器化实战
参考: https://www.centos.bz/2012/09/bind-with-mysql-support/ http://blog.51niux.com/?id=125 http://470 ...
- C#元祖Tuple的事例
数组合并了同样类型的对象.而元祖合并了不同类型的对象.元祖起源于函数编程语言(F#) NET Framework定义了8个泛型Tuple(自NET4.0)和一个静态的Tuple类,他们作用元祖的工厂, ...
- Activiti(一)--安装配置具体解释
有一段时间没有更新文章了,尽管有一直在写文章,但是一直没有更新到博客内,这段时间写的文章大多还是以技术为主. 接下来的系列文章将会来讨论企业工作流的开发,主要是来研究开源工作流Activiti的使用. ...
- c# 中的UserControl是什么 用户控件和自定义控件有什么区别
用户控件是许多控件的集成 自定义控件是自己写一个控件类,或者继承已有的控件类 复合控件是封装在公共容器内的 Windows 窗体控件的集合.这种控件有时称为“用户控件”.包含的控件称为“构成控件”. ...
- PHP——菜单及内容轮换(Jquery)
效果: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3. ...
- 解决java.lang.ClassNotFoundException: com.microsoft.sqlserver.jdbc.SQLServerDriver问题
今天在做项目的时候突然遇到解决java.lang.ClassNotFoundException: com.microsoft.sqlserver.jdbc.SQLServerDriver问题,知道是j ...
- 使用NPOI导入Excel注意日期格式和数字格式
//使用NPOI导入Excel public static DataTable importExcelToDataSetUsingNPOI(string FilePath, string fileNa ...
- 检索 COM 类工厂中 CLSID 为 {00024500-0000-0000-C000-000000000046} 的组件时失败解决方案
第一种方法测试过可用:地址:http://download.csdn.net/detail/itjjfamily/8853509 下面是第二种: .NET导出Excel遇到的80070005错误的解决 ...