重新学习 "运行时"(RunTime)

运行时:

Runtime, 通过字面理解, 是系统运行时候的一些机制. 它是OC中一套用C语言写的API

runtime机制在我们实际开发过程中经常体现出来, 比如:

1. 一个btn, 他的触发方法我们没有定义, 编译过程中, 只会提示警告, 但是在真正运行的时候, 就会crash

2. 无论MVC, MVVM框架, 我们都要创建Model, 在BaseModel中我们经常会会写这样一个方法, 只有在运行的时候, 才知道具体哪一个对象会调用这个方法

+ (instancetype)baseModelWithDic:(NSDictionary *)dic {

         id model = [[[self class] alloc] initWithDic:dic];

         return model;

}

runtime功能非常强大, 在很多优秀的第三方框架中都有用到, 首先来了解一下runtime有哪些功能

/*

runtime常用方法总结:

1.1 获得一个类所有的成员变量

      class_copyIvarList(Class cls , unsigned int *outCount)

1.2 获取类的成员变量的名字

      ivar_getName(Ivar v)

1.3 获取类的成员变量的类型

       ivar_getTypeEndcoding(Ivar v)

2.1 获取类的类方法

       class_getClassMethod((Class cls , SEL name)

2.2 获取类的实例变量方法

       class_getInstanceMethod(Class cls , SEL name)

2.3 交换两个方法

       method_exchangeImplementations(Method m1 , Method m2)

3.1 将值存储到对象的object中

       objc_setAssociatedObject(id object , const void *key ,id value ,objc_AssociationPolicy policy)

3.2 根据key 取出object中存储的值

       objc_getAssociatedObject(id object , const void *key)

*/


一. runtime实现了哪些Obj-C实现不了的功能

1. 获得某个类所有的成员变量, 成员方法;

2. 为一个类动态添加成员变量, 成员方法;

3. 动态交换两个方法

4. 发送消息

二. 利用runtime我们可以做哪些工作

1. 实现一个自定义的对象完成本地存储, 我们需要一一的对每一个属性进行decodeObjectForKey: 和 encodeObject:

我们可以利用class_copyIvarList方法获取当前类的所有成员变量, 然后遍历, 再利用ivar_getName将成员变量的名字当做key进行归档解档, 从而实现自动归解档, 无需考虑实际有多少个变量(获取当前类的所有成员变量)

这样如果属性多了, 或者后期经常添加或修改属性, 那就会非常的麻烦, 所以, 我们可以利用runtime的'能获取类所有的成员变量'这个方法, 动态的对该对象进行自动归档,解档

2. 给Category动态的添加属性(为一个类添加成员变量成员方法)

之前提过, Category只能添加方法, 不能添加属性, 但是我们可以用runtime给Category添加属性, 这里我们利用的是objc_setAssociatedObject方法将值关联到设置的属性上

例如: 给UIViewController添加一个副标题属性

1->首先我们需要在声明文件中声明一个属性:

#import@interface UIViewController (Subhead)

@property(nonatomic, copy) NSString *subHead;

@end

2->接着在实现文件中引runtime头文件

       set, get方法内部是根据键值来存取的, 我们需要给这个属性定义个key, 然后让set, get方法中根据这个key来存取属性的值

#import "UIViewController+Subhead.h"

#import <objc/runtime.h>

NSString *const kName = @"name";

@implementation UIViewController (Subhead)

// 重写set方法

- (void)setSubHead:(NSString *)subHead {

objc_setAssociatedObject(self, (__bridge const void *)(kName), subHead, OBJC_ASSOCIATION_COPY_NONATOMIC);

}

- (NSString *)subHead {

return objc_getAssociatedObject(self, (__bridge const void *)(kName));

}

@end

3. 开发中, 我们经常为了给运营统计数据, 会统计页面或按钮点击次数, 停留时间(方法的拦截, 用自己定义的方法与系统自带的方法交换)

首先我们要给UIViewController创建一个类目:Swizzling

#import "UIViewController+swizzling.h" 

#import@implementation UIViewController (swizzling)

+ (void)load {

[super load];

// 通过class_getInstanceMethod()函数获取当前类的方法

Method fromMethod = class_getInstanceMethod([self class], @selector(viewDidLoad));

Method toMethod = class_getInstanceMethod([self class], @selector(swizzlingViewDidLoad));

// 交换方法的实现

if (!class_addMethod([self class], @selector(viewDidLoad), method_getImplementation(toMethod), method_getTypeEncoding(toMethod))) {

method_exchangeImplementations(fromMethod, toMethod);

}

}

// 我们自己实现的方法,也就是和self的viewDidLoad方法进行交换的方法。

- (void)swizzlingViewDidLoad {

NSString *str = [NSString stringWithFormat:@"%@", self.class];

// 我们在这里加一个判断,将系统的UIViewController的对象剔除掉

if(![str containsString:@"UI"]){

NSLog(@"统计打点 : %@", self.class);

}

[self swizzlingViewDidLoad];   // 这里面实际调用的是原来的ViewDidLoad,因为此时已经被替换了

}

@end


结合runtime配合类目, 我们可以对归档解档进一步优化:

首先我们给NSObject写一个类目

声明文件中声明三个方法,忽略属性数组的get方法, 归档, 解档

#import@interface NSObject (Coder)

- (NSArray *)ignoreNames;

- (void)encode:(NSCoder *)enCode;

- (void)deCode:(NSCoder *)deCode;

@end

实现文件中, 只实现后两个方法

#import "NSObject+Coder.h"

#import <objc/runtime.h>

@implementation NSObject (Coder)

// 归档

- (void)encode:(NSCoder *)enCode {

// 从子类往父类进行查找,对父类的属性执行归解档方法

Class sClass = self.class;

while (sClass && sClass != [NSObject class]) {

unsigned int outCount = 0;

Ivar *ivars = class_copyIvarList([self class], &outCount);

for (int i = 0; i < outCount; i++) {

Ivar ivar = ivars[i];

NSString *key = [NSString stringWithUTF8String:ivar_getName(ivar)];

// 如果有需要忽略的Key 跳过归档

if ([self respondsToSelector:@selector(ignoredNames)]) {

if ([[self ignoreNames] containsObject:key]) continue;

}

id value = [self valueForKeyPath:key];

[enCode encodeObject:value forKey:key];

}

free(ivars);

sClass = [sClass superclass];

}

}

// 解档

- (void)deCode:(NSCoder *)deCode {

// 一层层父类往上查找,对父类的属性执行归解档方法

Class sClass = self.class;

while (sClass && sClass != [NSObject class]) {

unsigned int outCount = 0;

Ivar *ivars = class_copyIvarList(sClass, &outCount);

for (int i = 0; i < outCount; i++) {

Ivar ivar = ivars[i];

NSString *key = [NSString stringWithUTF8String:ivar_getName(ivar)];

// 如果有需要忽略的Key 跳过解档

if ([self respondsToSelector:@selector(ignoredNames)]) {

if ([[self ignoreNames] containsObject:key]) continue;

}

id value = [deCode decodeObjectForKey:key];

[self setValue:value forKey:key];

}

free(ivars);

sClass = [sClass superclass];

}

}

@end

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

推荐阅读更多精彩内容