runTime详解一
来源:互联网 发布:全国姓名数据库网址 编辑:程序博客网 时间:2024/06/05 03:36
Objective-C中调用对象的方法时, 会向该对象发送一条消息, runtime根据该消息做出反应.
Runtime是一套比较底层的纯C语言的API, Objective-C是运行在Runtime上的, 因此在Runtime中动态添加和实现一些非常强大的功能也就不足为奇了.
废话少说,开始正题!
一:runtime消息传递
(1)objc_msgSend
[receiver message] 会被编译器转化为: objc_msgSend(receiver, selector)
(2)类的定义
struct objc_class {
Class isa OBJC_ISA_AVAILABILITY;
#if !__OBJC2__
Class super_class;
//父类
const char *name;
//类名
long version;
//类的版本信息,默认为0
long info;
//类信息,供运行期使用的一些位标识
long instance_size;
//类的实例变量大小
struct objc_ivar_list *ivars;
// 类的成员变量链表
struct objc_method_list **methodLists;
// 方法链表
struct objc_cache *cache;
//方法缓存
struct objc_protocol_list *protocols;
//协议链表#
endif}
OBJC2_UNAVAILABLE;
有几个字段的解释
isa:需要注意的是在Objective-C中,所有的类自身也是一个对象,这个对象的Class里面也有一个isa指针,它指向metaClass(元类)
super_class:指向该类的父类,如果该类已经是最顶层的根类(如NSObject或NSProxy),则super_class为NULL。
cache:用于缓存最近使用的方法。一个接收者对象接收到一个消息时,它会根据isa指针去查找能够响应这个消息的对象。在实际使用中,这个对象只有
一部分方法是常用的,很多方法其实很少用或者根本用不上。这种情况下,如果每次消息来时,我们都是methodLists中遍历一遍,性能势必很差。这时,
cache就派上用场了。在我们每次调用过一个方法后,这个方法就会被缓存到cache列表中,下次调用的时候runtime就会优先去cache中查找,如果cache
没有,才去methodLists中查找方法。这样,对于那些经常用到的方法的调用,但提高了调用的效率。
version:我们可以使用这个字段来提供类的版本信息。这对于对象的序列化非常有用,它可是让我们识别出不同类定义版本中实例变量布局的改变。
针对cache,我们用下面例子来说明其执行过程:
NSArray *array = [[NSArray alloc] init];
其流程是:
[NSArray alloc]先被执行。因为NSArray没有+alloc方法,于是去父类NSObject去查找。
检测NSObject是否响应+alloc方法,发现响应,于是检测NSArray类,并根据其所需的内存空间大小开始分配内存空间,然后把isa指针指向NSArray类。同时,+alloc也被加进cache列表里面。
接着,执行-init方法,如果NSArray响应该方法,则直接将其加入cache;如果不响应,则去父类查找。
在后期的操作中,如果再以[[NSArray alloc] init]这种方式来创建数组,则会直接从cache中取出相应的方法,直接调用。
总的来说:就是当调用一个方法的时候,先到cache中寻找,如果相应,则返回,如果没有则在子类的methodLists遍历一边,如果有则返回,如果没有就去父类中查找遍历,直到根类。
二:runTime的应用
runTime共有我总结的有以下几种:获取类的名字,属性和方法,关联对象,动态添加,删除,修改方法,方法交互,拦截调用等,下面一个一个进行说明
(1)获取类的名字,属性和方法:(应用场景:dictionary转model,获取某类的属性,方法,名字)
Dome链接:
//获取变量列表
//入参:类Class,int变量指针
//返回:变量信息Ivar列表
//* 1.获取所有私有变量和属性对应的变量
//* 2.获取的私有变量的名和定义的名一样
//* 3.获取的属性的名前面都添加了下划线
//* 4.不能获取Category添加的变量(动态绑定的变量)
Ivar *class_copyIvarList(Class cls, unsigned int *outCount)
//获取属性列表(只获取属性不获取变量)
//入参:类Class,int变量指针
//返回:属性信息objc_property_t列表
//* 1.获取所有属性
//* 2.获取的属性名和你代码写的一样,获取出来的属性名不自动添加下划线
//* 3.不能获取Category添加的属性。
objc_property_t *class_copyPropertyList(Class cls, unsigned int *outCount)
//获取方法列表
//入参:类Class,int变量指针
//返回:方法信息Method列表
//* 1.获取所有实例方法,不包含静态方法
//* 2.不获取父类的方法
//* 3.隐式的get set 方法也能获取到
//* 4.可以获取分类和动态添加的方法。
Method *class_copyMethodList(Class cls, unsigned int *outCount)
//获取协议列表
//入参:类Class,int变量指针
//返回:方法协议Protocol列表
//* 1.不能获取分类实现的协议
Protocol * __unsafe_unretained *class_copyProtocolList(Class cls, unsigned int *outCount)
unsigned int copyIvarListCount = 0;
Ivar *ivars = class_copyIvarList([self class], ?IvarListCount);
for
(NSInteger i = 0; i< copyIvarListCount; i ++) {
Ivar ivar = ivars[i];
const char *name = ivar_getName(ivar);
NSLog(@
">>>>>>>>0:class_copyIvarList:%s"
,name);
}
free(ivars);
//释放
NSLog(@
"\n"
);
//class获取--获取整个属性列表(只获取属性不获取变量)
/**
* 1.获取所有属性
* 2.获取的属性名和你代码写的一样,获取出来的属性名不自动添加下划线
*/
unsigned int copyPropertyListCount = 0;
objc_property_t *propertys = class_copyPropertyList([self class], ?PropertyListCount);
for
(NSInteger i = 0; i < copyPropertyListCount; i++) {
objc_property_t property = propertys[i];
const char *name = property_getName(property);
NSLog(@
">>>>>>>>1:copyPropertyList:%s"
,name);
}
free(propertys);
//释放
NSLog(@
"\n"
);
//class获取--获取整个类的实例方法的方法列表
/**
* 1.获取所有实例方法,不包含静态方法
* 2.不获取父类的方法
* 3.隐式的get set 方法也能获取到
*/
unsigned int copycopyMethodListCount = 0;
Method *methods = class_copyMethodList([self class], ?copyMethodListCount);
for
(NSInteger i = 0; i < copycopyMethodListCount; i++) {
Method method = methods[i];
SEL name = method_getName(method);
NSLog(@
">>>>>>>>2:copyMethodList:%@"
,NSStringFromSelector(name));
}
free(methods);
//释放
NSLog(@
"\n"
);
//添加--协议
/**
* 1.class_addProtocol 参数含义:第一个:要添加协议的类,第二个:协议对象
* 2.获取协议列表具体细节参照Class1里的内容
*/
unsigned int copyProtocolListCount = 0;
Protocol * __unsafe_unretained *protocals = class_copyProtocolList([self class], ?ProtocolListCount);
for
(NSInteger i = 0; i < copyProtocolListCount; i++) {
Protocol * protocal = protocals[i];
const char *name = protocol_getName(protocal);
NSLog(@
">>>>>>>>3:copyProtocolList:%s"
,name);
}
free(protocals);
//释放
NSLog(@
"\n"
);
}
(2)关联对象 (应用场景:在Category添加属性)
方法声明:
void objc_setAssociatedObject ( id object, const void *key, id value, objc_AssociationPolicy policy );
描述:使用给定的键和关联策略设置给定对象的关联值。
object:关联的源对象;
key:给定的键;在设置关联对象值时,若想令两个键匹配到同一个值,则二者必须是完全相同的指针才行,鉴于此,在设置关联对象值时,通常使用静态全局变量做键;
value:与对象关联的键key的对象。如果为nil则清空当前的关联。
policy:关联的策略如下图
方法声明:
id objc_getAssociatedObject ( id object, const void *key );
描述:返回关联到给定对象为给定的键的值。返回值就是上面方法中相同key的value对象;
方法声明:
void objc_removeAssociatedObjects ( id object );
描述:移除指定对象的所有关联值;这个函数的主要目的轻松的返回一个对象的“原始状态”。您不应该使用此功能来删除对象的关联,因为它也将移除了其他客户端添加到对象的关联。你应该通过给objc_setassociatedobject方法传递nil来明确清空你要取消关联的值。
举例:
static void* MyAlertViewKey = "MyAlertViewKey";
UIAlertView *alert = [[UIAlertView alloc]initWithTitle:@"Question" message:@"What do you want to do?" delegate:self cancelButtonTitle:@"Cancel" otherButtonTitles:@"Continue", nil]; void(^block)(NSInteger) = ^(NSInteger buttonIndex){ if (buttonIndex == 0) { [self doCancel]; } else { [self doContinue]; } }; objc_setAssociatedObject(alert, MyAlertViewKey, block, OBJC_ASSOCIATION_COPY); [alert show];
#pragma mark - UIAlertViewDelegate-(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex{ void(^block)(NSInteger) = objc_getAssociatedObject(alertView, MyAlertViewKey); block(buttonIndex);}
注意:使用关联对象要注意循环引用的问题,上面的功能也可以通过继承来更好地实现;
- runTime详解一
- Runtime详解一
- RunTime机制详解(一)
- Runtime(一) 初识runtime
- RunTime(一)
- runtime (一)
- runtime(一)
- Runtime详解
- runtime详解
- runtime 详解
- runtime详解
- Runtime详解
- runtime详解
- runtime 详解
- runtime 详解
- RunTime详解-------
- Runtime详解
- runtime详解
- 中间件通俗理解
- hadoop复合键排序使用方法
- 解决android studio错误 --> Error:(1, 0) Plugin with id 'com.android.application' not found
- Xib文件拖控件关联时候报错:“Could not insert new outlet connection”
- Java 开发基于Zookeeper,Spring,vue.js的高并发多用户模块化微信商城系统(一) 项目介绍
- runTime详解一
- PHP实现在手机上选择完图片直接上传图片
- ExtJS 4.2 树形结构请求后台数据无法展示子节点,而是没点击一次请求一次数据,无限请求加载所有的父节点元素
- 将QML与Qt Widgets相结合
- pyhton基础
- 【汇编】win10环境下debug程序的进入与使用
- 最长匹配子序列 和 删除次数最小形成回文
- linux设备驱动模型之class
- mybatis的入门使用