首页 > 代码库 > runtime 运行时机制[转]

runtime 运行时机制[转]

转自:http://my.oschina.net/panyong/blog/297640

 

 

对于runtime机制,在网上找到的资料大概就是怎么去用这些东西,以及查看runtime.h头文件中的实现,当然这确实是一种很好的学习方法,但是,其实我们还是不会知道runtime底层编译成C++语言之后做了什么?
查到一个大牛给资料,顿时对runtime有了一定认识!

我们随便写一个小程序,代码如下:
person类头文件如下,

1 #import <Foundation/Foundation.h>2 @interface Person : NSObject3 4 @property (nonatomic, strong) NSString *name; 5 @property (nonatomic, assign) int age;6 7 @end

main.m文件如下

 1 int main(int argc, const char * argv[]) 2  3 Person *p = [[Person alloc] init]; 4  5 NSString *str = @"zhangsan"; 6  7 p.name = str; 8 // p.name 等价于 9 [p setName:str];10 11 p.age = 20;12 13 return 0;14 }

然后我们打开终端,在命令行找到cd到文件目录,然后中输入:

clang -rewrite-objc main.m
命令可以将main.m编译成C++的代码,改成不同的文件名,就会生成不同的c++代码
这是就生成了main.cpp这个c++文件,打开文件代码
查看该main.cpp最底下的main函数,
这样我们就可以看到底层具体实现的方式!

这时,我们就需要知道这些方法:
objc_msgSend 可以给对象发送消息
objc_getClass(“Person”) 可以获取到指定名称的对象
sel_registerName(“alloc”) 可以调用到对象的方法

通过查看,c++代码,我们得出结论:
使用objc_msgSend函数,给objc_getClass函数实例化的对象发送sel_registerName获取到的方法
这么一个消息
代码是给人看的,顺带让机器实现功能。日常的程序开发过程中,要少用runtime,

那什么时候会使用runtime呢?
runtime应用的时机:
1> 当需要非常高的性能开发时,使用runtime,注释:oc的代码已经无法满足性能需求
2> 当我们对系统内部的实现很好奇的时候,可以用clang反编译成c++去看底层的实现机制!

最后,我知道我写的这篇博客可能不是很好,或者读者觉得有什么不对的地方,希望能给我指出来,大家共同进步!

项目讲解的是runtime的底层实现原理, 如果想要知道runtime是怎么用的,可以查看runtime.h头文件查看!
以下是runtime机制方法的一些使用方法介绍,希望对大家有用!
相关技术文档:http://www.tuicool.com/articles/uimInm
http://blog.csdn.net/lengshengren/article/details/17764135

 

转自:http://my.oschina.net/panyong/blog/298631#OSC_h1_1

我们前面已经讲过一篇runtime 原理,现在这篇文章主要介绍的是runtime是什么以及怎么用!希望对读者有所帮助!

首先,第一个问题,
1》runtime实现的机制是什么,怎么用,一般用于干嘛?
这个问题我就不跟大家绕弯子了,直接告诉大家,
runtime是一套比较底层的纯C语言API, 属于1个C语言库, 包含了很多底层的C语言API。
在我们平时编写的OC代码中, 程序运行过程时, 其实最终都是转成了runtime的C语言代码, runtime算是OC的幕后工作者
比如说,下面一个创建对象的方法中,
举例:
OC :
[[MJPerson alloc] init]
runtime :
objc_msgSend(objc_msgSend(“MJPerson” , “alloc”), “init”)

第二个问题
runtime 用来干什么呢??用在那些地方呢?怎么用呢?
runtime是属于OC的底层, 可以进行一些非常底层的操作(用OC是无法现实的, 不好实现)

在程序运行过程中, 动态创建一个类(比如KVO的底层实现)

在程序运行过程中, 动态地为某个类添加属性\方法, 修改属性值\方法

遍历一个类的所有成员变量(属性)\所有方法
例如:我们需要对一个类的属性进行归档解档的时候属性特别的多,这时候,我们就会写很多对应的代码,但是如果使用了runtime就可以动态设置!
例如,PYPerson.h的文件如下所示

 1 import 2 @interface PYPerson : NSObject  3 @property (nonatomic, assign) int age;  4 @property (nonatomic, assign) int height;  5 @property (nonatomic, copy) NSString *name;  6 @property (nonatomic, assign) int age2;  7 @property (nonatomic, assign) int height2;  8 @property (nonatomic, assign) int age3;  9 @property (nonatomic, assign) int height3; 10 @property (nonatomic, assign) int age4; 11 @property (nonatomic, assign) int height4;12 13 @end

而PYPerson.m实现文件的内容如下

 1 #import "PYPerson.h" 2 @implementation PYPerson 3  4 -(void)encodeWithCoder:(NSCoder )encoder  5 {  6   unsigned int count = 0;  7   Ivar ivars = class_copyIvarList([PYPerson class], &count); 8  9   for (int i = 0; i<count; i++) {10 11     // 取出i位置对应的成员变量12     Ivar ivar = ivars[i];13 14     // 查看成员变量15     const char *name = ivar_getName(ivar);16 17     // 归档18     NSString *key = [NSString stringWithUTF8String:name];19     id value =http://www.mamicode.com/ [self valueForKey:key];20     [encoder encodeObject:value forKey:key];21   }22 23   free(ivars); 24 }25 26 -(id)initWithCoder:(NSCoder *)decoder 27 { 28   if (self = [super init]) {29 30     unsigned int count = 0;31     Ivar *ivars = class_copyIvarList([PYPerson class], &count);32 33     for (int i = 0; i<count; i++) {34       // 取出i位置对应的成员变量35       Ivar ivar = ivars[i];36 37       // 查看成员变量38       const char *name = ivar_getName(ivar);39 40       // 归档41       NSString *key = [NSString stringWithUTF8String:name];42       id value =http://www.mamicode.com/ [decoder decodeObjectForKey:key];43 44       // 设置到成员变量身上45       [self setValue:value forKey:key];46     }47 48     free(ivars);49   } 50   return self; 51 }52 53 @end

 

这样我们可以看到归档和解档的案例其实是runtime写下的

学习,runtime机制首先要了解下面几个问题
1相关的头文件和函数
1> 头文件


利用头文件,我们可以查看到runtime中的各个方法!
2> 相关应用

NSCoding(归档和解档, 利用runtime遍历模型对象的所有属性)
字典 –> 模型 (利用runtime遍历模型对象的所有属性, 根据属性名从字典中取出对应的值, 设置到模型的属性上)
KVO(利用runtime动态产生一个类)
用于封装框架(想怎么改就怎么改)
这就是我们runtime机制的只要运用方向
3> 相关函数

objc_msgSend : 给对象发送消息
class_copyMethodList : 遍历某个类所有的方法
class_copyIvarList : 遍历某个类所有的成员变量
class_…..
这是我们学习runtime必须知道的函数!
4.必备常识
1> Ivar : 成员变量
2> Method : 成员方法
从上面例子中我们看到我们定义的成员变量,如果要是动态创建方法,可以使用Method,

 

转自:http://www.cnblogs.com/hanjun/archive/2013/04/08/3006999.html

oc是一个全动态语言,oc的一切都是基于runtime实现的!

从以下三方面来理解runtime吧!

1. 传统的面向过程的语言开发,例如c语言。实现c语言编译器很简单,只要按照语法规则实现一个LALR语法分析器就可以了,编译器优化是非常难的topic,不在这里讨论范围内,忽略。 这里我们实现了编译器其中最最基础和原始的目标之一就是把一份代码里的函数名称,转化成一个相对内存地址,把调用这个函数的语句转换成一个jmp跳转指令。在程序开始运行时候,调用语句可以正确跳转到对应的函数地址。 这样很好,也很直白,但是。。。太死板了。everything is per-determined

2. 我们希望灵活,于是需要开发面向对象的语言,例如c++。 c++在c的基础上增加了类的部分。但这到底意味着什么呢?我们在写它的编译器要如何考虑呢?其实,就是让编译器多绕个弯,在严格的c编译器上增加一层类处理的机制,把一个函数限制在它处在的class环境里,每次请求一个函数调用,先找到它的对象, 其类型,返回值,参数等等,确定了这些后再jmp跳转到需要的函数。这样很多程序增加了灵活性同样一个函数调用会根据请求参数和类的环境返回完全不同的结果。增加类机制后,就模拟了现实世界的抽象模式,不同的对象有不同的属性和方法。同样的方法,不同的类有不同的行为! 这里大家就可以看到作为一个编译器开发者都做了哪些进一步的思考。但是。。。还是死板, 我们仍然叫c++是static language。

3. 希望更加灵活! 于是我们完全把上面哪个类的实现部分抽象出来,做成一套完整运行阶段的检测环境。这次再写编译器甚至保留部分代码里的sytax名称,名称错误检测,runtime环境注册所有全局的类,函数,变量等等信息等等,我们可以无限的为这个层增加必要的功能。调用函数时候,会先从这个运行时环境里检测所以可能的参数再做jmp跳转,这就是runtime。编译器开发起来比上面更加弯弯绕。但是这个层极大增加了程序的灵活性。  例如当调用一个函数时候,前2种语言,很有可能一个jmp到了一个非法地址导致程序crash, 但是在这个层次里面,runtime就过滤掉了这些可能性。 这就是为什么dynamic langauge更加强壮。 因为编译器和runtime环境开发人员已经帮你处理了这些问题。

好了上面说着这么多,我们再返回来看objective-c.  现在你是不是能理解这样的语句了呢?
    id obj=self;
    if ([obj respondsToSelector:@selector(function1:)) {
    }
    if ([obj isKindOfClass:[NSArray class]] ) {
    }
    if ([obj conformsToProtocol:@protocol(myProtocol)]) {
    }           
    if ([[obj class] isSubclassOfClass:[NSArray class]]) {
    }
    [obj someNonExistFunction];


看似很简单的语句,但是为了让语言实现这个能力,语言开发者要付出很多努力实现runtime环境。这里运行时环境处理了弱类型函数存在检查工作。runtime会检测注册列表里是否存在对应的函数,类型是否正确,最后确定下来正确的函数地址,再进行保存寄存器状态,压栈,函数调用等等实际的操作。

    id knife=[Knife grateKnife];
    NSArray *monsterList=[NSArray array];
    [monsterList makeObjectsPerformSelector:@selector(killMonster:) withObject:knife];

在c,c++年代去完成这个功能是非常麻烦的,但是动态语言却非常简单。

关于执行效率问题。 “静态语言执行效率要比动态语言高”,这句没错。因为一部分cpu计算损耗在了runtime过程中。而静态语言生成的机器指令更简洁。正因为知道这个原因,所以开发语言的人付出很大一部分努力为了保持runtime小巧上。所以objecitve-c是c的超集+一个小巧的runtime环境。  但是,换句话说,从算法角度考虑,这点复杂度不算差别的,Big O notation结果不会有差别。( It‘s not log(n) vs n^2 )

简单理解:“Runtime is everything between your each function call.” 
Runtime好比objective-c的灵魂。很多东西都是在这个基础上出现的。所以它是指的你花功夫去理解的。

 

转自:http://www.cnblogs.com/zander/archive/2012/07/18/2597567.html

nsarray 类定义的方法

1.  makeObjectsPerformSelector:@select(aMethod)

简介:让数组中的每个元素 都调用 aMethod 

2. makeObjectsPerformSelector:@select(aMethod) withObject:oneObject

简介:让数组中的每个元素 都调用 aMethod  并把 withObject 后边的 oneObject 对象做为参数传给方法aMethod

[array makeObjectsPerformSelector:@selector(setRecurringDelegate:) withObject:self];/*检测到的该自动插入的交易插入数据库*/

[array makeObjectsPerformSelector:@selector(insertRecursion)]; /*检测到的该自动插入的交易插入数据库*/

runtime 运行时机制[转]