Runtime 的应用(四)

前面我们说到:
Runtime 消息传递机制
Runtime 消息转发机制
Runtime 交换方法
今天我们来谈谈Runtime的一些常用的用法

1.KVO的底层实现

KVO:Key-Value-Observe 键值监听,动态监听属性的变化
具体用法

//这里以监听Person的age属性为例
self.person = [Person new];
self.person.age = 21;
//此行注册监听 
[self.person addObserver:self forKeyPath:@"age" options:NSKeyValueObservingOptionNew context:nil];

然后实现如下方法,当每次age改变,都会调用下面的方法

-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context{
    NSLog(@"%@监听到%@属性的改变为%@",object,keyPath,change);
}

那么KVO是怎么实现的呢?

1、自定义当前类的子类
2、重写set方法,在内部恢复父类的做法,通知观察者
3、通过修改当前类对象的isa指针,指向自定义的子类来让外界调用自定义类的方法
//此行注册监听后,利用Runtime在程序运行过程中,改变了这个对象的类型:NSKVONotifing_Person  
[self.person addObserver:self forKeyPath:@"age" options:NSKeyValueObservingOptionNew context:nil];

而生成的NSKVONotifing_Person类中会重写age的set方法

/** 重写set方法 */
-(void)setAge:(int)age{
    [super setAge:age];
    //这两个方法会默认调用观察者的observeValueForKeyPath方法
    [self willChangeValueForKey:@"age"];
    [self didChangeValueForKey:@"age"];
}

原来是在重写的set方法里面做了手脚。

如下是没有设置监听age属性时,对Person的断点调试


image.png

如下是设置监听age属性后,对Person的断点调试


image.png

2.获取对象的所有(包括私有)属性、变量、方法

2.1获取对象的所有属性

- (IBAction)allProperty:(id)sender {
    
    // 定义变量
    unsigned int count;
    // 运行时获取私有属性列表
    objc_property_t *properties = class_copyPropertyList([Person class], &count);

    for (int index = 0; index < count; ++index) {
        // 声明属性
        objc_property_t property = properties[index];

        // 指针数组. 通过property_getName获取属性的名称
        const char *cName = property_getName(property);
        // UTF8转码
        NSString *name = [NSString stringWithUTF8String:cName];
        NSLog(@"name -----> %@", name);
    }
    
    free(properties);
}

2.2获取对象的所有属性+变量

- (IBAction)allIvar:(id)sender {
    
    unsigned int count = 0;
    Ivar * ivars = class_copyIvarList([Person class], &count);
    for (int i = 0; i < count; i++) {
        //拿出属性的名称
        Ivar ivar = ivars[I];
        const char * name = ivar_getName(ivar);
        NSString * KEY = [NSString stringWithUTF8String:name];
        NSLog(@"name -----> %@", KEY);
    }
    
    //c语言里面需要释放指针!!
    free(ivars);
    
}

2.3获取对象的所有方法

- (IBAction)allMethod:(UIButton *)sender {
    
    // 定义变量
    unsigned int count;
    // 运行时获取私有方法列表
    Method *methods = class_copyMethodList([Person class], &count);
    
    for (int index = 0; index < count; ++index) {
        Method method = methods[index];
        
        // 这步完了之后, 可以获取到方法的地址
        SEL selector = method_getName(method);
        
        NSString *name = NSStringFromSelector(selector);
        // 确定方法类型
        const char *type = method_getTypeEncoding(method);
        NSLog(@"fun-----%@,  type-----> %s",name,type);
    }
    free(methods);
}

3.序列化与反序列化

还记得当初代码里面关于序列化与反序列化的代码一堆一堆的

image.png

如上是属性比较少的,我看到过多的有上百行的,简直要翻好几页才能看完,更何况是写呢?
你是不是也想过简化这段代码,现在,可以用runtime来简化

#import "CodingModel.h"
#import <objc/runtime.h>
@implementation CodingModel
- (void)encodeWithCoder:(NSCoder *)coder
{
    unsigned int count = 0;
    Ivar * ivars = class_copyIvarList([self class], &count);
    for (int i = 0; i < count; i++) {
        //拿出属性的名称
        Ivar ivar = ivars[i];
        const char * name = ivar_getName(ivar);
        NSString * KEY = [NSString stringWithUTF8String:name];
        //取出属性的值
        id value = [self valueForKey:KEY];
        //归档
        [coder encodeObject:value forKey:KEY];
    }
    
    //c语言里面需要释放指针!!
    free(ivars);
}

//解档!!
- (instancetype)initWithCoder:(NSCoder *)coder
{
    self = [super init];
    if (self) {
        unsigned int count = 0;
        Ivar * ivars = class_copyIvarList([self class], &count);
        for (int i = 0; i < count; i++) {
            //拿出属性的名称
            Ivar ivar = ivars[i];
            const char * name = ivar_getName(ivar);
            NSString * KEY = [NSString stringWithUTF8String:name];
            //解档
            id value = [coder decodeObjectForKey:KEY];
            //将值设置到属性上 KVC
            [self setValue:value forKey:KEY];
        }
        
        //c语言里面需要释放指针!!
        free(ivars);
    }
    return self;
}
@end

哈哈,总共20行,搞定
你可以写个基类,在需要用到序列化的Model里直接继承这个基类。搞定

文章就到这里
提供一份Demo,希望对你有帮助
想了解更多RunTime,可以参考:
Runtime 消息传递机制
Runtime 消息转发机制
Runtime 交换方法

写在最后:
希望这篇文章对您有帮助。当然如果您发现有可以优化的地方,希望您能慷慨的提出来。最后祝您工作愉快!

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

推荐阅读更多精彩内容

  • 1.class 类 2.public 公开的 3.private 私有的 4.static 静态的 5.packa...
    李洋codingfarmer阅读 168评论 0 0
  • “金无足赤,人无完人”。我常常这样安慰自己,也总是想着缺憾也是一种美!可是,在内心深处,却总是不会这样思考...
    七月沐风阅读 471评论 1 2
  • 秘密7/30 美乐爱觉日精进打卡344天 1.晨起早起坐地铁去跳灵性舞蹈,好棒啊!一路上都在学习大悲咒,祝福所有人...
    曾小杰爱码字阅读 163评论 0 0
  • 视频上的女子光着脚,没穿内衣,在哭喊,男子不管不顾地继续施暴,把她粗鲁的放到后座,整个公交车上的人都袖手旁观。 很...
    沐阳and阅读 387评论 0 2