runtime的作用及实例

什么是runtime

runtime是底层的纯C语言的API,它包含的很多底层的语法。
我们平时编写的OC代码,在程序运行过程中,最终都是转化成了runtime的C语言代码,
runtime也称为运行时,它是OC的幕后工作者。

runtime的作用

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];

具体操作


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
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,734评论 6 505
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,931评论 3 394
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,133评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,532评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,585评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,462评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,262评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,153评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,587评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,792评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,919评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,635评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,237评论 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,855评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,983评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,048评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,864评论 2 354

推荐阅读更多精彩内容