runtime
2015-10-03 15:01
465 查看
用
runtime主要就是做一些底层的操作,如: 1. 动态的添加对象的成员变量和方法 2.动态交换两个方法的实现(可以替换系统的方法) 3.获得某个类的所有成员方法、所有成员变量 4. 实现分类也可以添加属性 5.实现NSCoding的自动归档和解档 6.实现字典转模型的自动转换
替换系统方法,可以通过拦截系统的方法探究底层,比如block 的实现原理
常用方法
1.获取类中的方法Method class_getClassMethod(Method cls , SEL name)
如:
Method m = class_getClassMethod([Person class],@selector(setName:));
2.获取对象中的方法
Method class_getInstanceMethod(Method cls, SEL name)
如:
Person *person = [[Person alloc] init]; Method m = get_InstanceMethod([person class],@selector(setName:));
3.交换两个方法的实现
void method_exchangeImplementations(Method m1,Method m2)
如
Person *p =[[Person alloc] init]; [p study]; [p run]; //交换实现 //instance method :实例方法, //class_getInstanceMethod得到实例的方法(即对象方法) //两个参数 1:类名 2.方法名 //class_getClassMethod :得到实例化的方法 Method m1 = class_getInstanceMethod([Person class], @selector(study)); Method m2 = class_getInstanceMethod([Person class], @selector(run)); method_exchangeImplementations(m2, m1); [p study]; [p run];
具体操作
![](http://upload-images.jianshu.io/upload_images/922910-4613676111601f51.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
051B23EE-AFC6-4C95-9297-1E58708D5B96.png
4.获取成员变量
Ivar *ivars = class_getCopyIvarList(Ivar ivar);
实现分类中添加属性
为所有的NSObject对象添加属性1.首先创建一个NSObject分类NSObject+Extension
2.在.h中使用@property添加属性
此时使用@property添加数属性,并非真正的属性,如果此时调用查看属性,将会崩溃, 因为分类并未实现添加添加属性的功能,想要添加属性,需要使用runtime,动态的添加
3.在.m文件中实现getter和setter方法
如果想要添加多个属性,就需要在每个对象中抽出一块空间用于存放属性, 使用objc_setAssociatedObject方法进行关联 #import "NSObject+Extension.h" #import <objc/runtime.h> @implementation NSObject (Extension) //用于存放属性的变量,多个属性,需要创建不同的变量 char BookKey; -(void)setBooks:(NSArray *)books{ objc_setAssociatedObject(self, &BookKey, books, OBJC_ASSOCIATION_RETAIN_NONATOMIC); } -(NSArray *)books{ return objc_getAssociatedObject(self, &BookKey); } @end
遵守协议NSCoding,实现属性的自动归档与解档
需求分析:当想要对象自动进行归档解档的时候,如果属性非常的多,一个一个天添加[encoder encodeObject:@(xxx) forKey:@"_xxx"];将会非常的繁琐。
既然能够获取所有的属性,我们就可以通过循环遍历属性的方式进行统一的归档和解档
- (id)initWithCoder:(NSCoder *)decoder { if (self = [super init]) { // 用来存储成员变量的数量 unsigned int outCount = 0; // 获得Dog类的所有成员变量 Ivar *ivars = class_copyIvarList([self class], &outCount); // 遍历所有的成员变量 for (int i = 0; i<outCount; i++) { // 取出i位置对应的成员变量 Ivar ivar = ivars[i]; NSString *key = [NSString stringWithUTF8String:ivar_getName(ivar)]; // 获得key对应的值 id value = [decoder decodeObjectForKey:key]; // 设置到成员变量上 [self setValue:value forKeyPath:key]; } free(ivars); } return self; } /** * 将对象写入文件时会调用这个方法(开发者需要在这个方法中说明需要存储哪些属性) */ - (void)encodeWithCoder:(NSCoder *)encoder { // 用来存储成员变量的数量 unsigned int outCount = 0; // 获得Dog类的所有成员变量 Ivar *ivars = class_copyIvarList([self class], &outCount); // 遍历所有的成员变量 for (int i = 0; i<outCount; i++) { // 取出i位置对应的成员变量 Ivar ivar = ivars[i]; NSString *key = [NSString stringWithUTF8String:ivar_getName(ivar)]; // 通过key获得对应成员变量的值 id value = [self valueForKeyPath:key]; [encoder encodeObject:value forKey:key]; } free(ivars); }
注意:
ARC的内存管理机制 只适合OC语法,对于C语言的内存还是需要手动的释放,当使用runtime的时候, 如果包含了copy、create、retain、new等词语,那么在最后就需要释放内存 使用free(对象)进行释放如:free(ivars);
利用runtime实现字典转模型
描述:KVC的字典转模型具有一个缺陷,就是属性的数量与名称都必须保持一致,如果字典中的属性多, 而模型中没有使用KVC赋值的时候就会崩溃,需要实现另一个方法 setValue:forUndefinedKey:方法,并如果对象中包含了另一个对象作为属性, 也将不能自动将其转化为模型 而使用runtime实现的字典转模型,可以实现将所有的对象都转化为对应的模型, 并且不会出现属性找不到,而奔溃的现象
NSObject+Extension.h
#import <Foundation/Foundation.h> @interface NSObject (Extension) -(void)setDiction:(NSDictionary *)dict; +(instancetype)objectWithDiction:(NSDictionary *)dict; @end
NSObject+Extension.m
#import "NSObject+Extension.h" #import <objc/runtime.h> @implementation NSObject (Extension) -(void)setDiction:(NSDictionary *)dict{ //获取类 Class c = self.class; //循环遍历 类 (本类 和所有的父类) while (c && c != [NSObject class]) { //获取所有的属性 unsigned int outCount = 0; Ivar *ivars = class_copyIvarList(c, &outCount); //遍历类中的属性 for (int i = 0; i < outCount; i++) { //获取属性名 Ivar ivar = ivars[i]; NSString *key = [NSString stringWithUTF8String:ivar_getName(ivar)]; //去掉key中的 _ key = [key substringFromIndex:1]; //通过key 获取属性的值 id value = dict[key]; //如果key是一个空值 退出本轮的循环 //原因:如果字典中没有这个key,那么value将会是一个空值,kvc 不能赋值空值 if (value == nil) { continue; } //如果类中包含另一个类为对象,也要将该对象进行字典转模型 //获取对象的属性的类名 NSString *type = [NSString stringWithUTF8String:ivar_getTypeEncoding(ivar)]; // 对象名会以@“名字”的形式 出现,但是同时字符串也是以这种形式表示,因此可以先判断type中是否包含 @ 符号 NSRange range = [type rangeOfString:@"@"]; //如果range.location 不等于NSNotFound说明 找到了@ if (range.location != NSNotFound) { //截取type中的名字 去除@“ ” type = [type substringWithRange:NSMakeRange(2, type.length -3)]; if (![type hasPrefix:@"NS"]) { //将type转化为类名 Class class = NSClassFromString(type); value = [class objectWithDiction:value]; } } //赋值 [self setValue:value forKey:key]; } //ARC 只适用于OC语法,C语言中的内存 需要手动释放 free(ivars); c = [c superclass]; NSLog(@"1"); } } +(instancetype)objectWithDiction:(NSDictionary *)dict{ NSObject *obj = [[self alloc] init]; [obj setDiction:dict]; return obj; } @end
相关文章推荐
- 通过 虚函数 来实现多态
- oponcv运行时无法找到、打开PDB文件(cannot find or open pdb file),程序已经退出,返回值-1(0xffffff)
- new,delete,malloc,free
- cocos2dX 3.x获取渲染Image
- c程序无法输入字符(程序无反应)的原因!
- 进程组 http://blog.163.com/li_xiang1102/blog/static/60714076201110294573495/
- Hibernate Mysql 逆向工程,外键映射
- 使用sp_addextendedproperty添加描述信息
- 面向对象和界面设计
- javascript基础(下)
- 会话、进程组、进程个人理解。http://bbs.chinaunix.net/thread-2176051-1-1.html
- HDU 2187 悼念512汶川大地震遇难同胞——老人是真饿了(贪心)
- Search for a Range
- Java学习笔记 ---对象和类
- Alloc 和 AllocWithZone的区别
- 3、Hibernate实现简单的CRUD操作
- 编写驱动学习
- 1.3.1 关中断并将system移动到内存地址起始位置0x00000
- 项目管理-范围管理
- mysql 学习记录(四)--数值计算、逻辑判断、范围选择、位运算