美文网首页iOS开发iOS资料汇总 ios零碎记录
再来看看费脑的Runtime-实用篇

再来看看费脑的Runtime-实用篇

作者: 纸简书生 | 来源:发表于2016-03-21 12:00 被阅读163次

开篇

关于Runtime,在平时的开发中,我用得最多的就是方法混淆(Method Swizzling)和动态添加属性.虽然自己经常用,但是很少去深究原理性的东西.今天就重温一下费脑的runtime;

使用场景

runtime的使用场景我总结一下,大致分为如下几种,由浅入深.并且附上相关示例代码:
  • 1.给分类添加属性
    目前常用的两种方式,一种是显示定义定义属性关联的key,一种是直接通过方法名作为属性关于的key.
    显示定义关联的key
Paste_Image.png

** 直接通过方法名定义关联的key**

隐试关联.png
  • 2.方法混淆(Method Swizzling)
    方法混淆在实际开发中我就用到统计每个页面进入与退出的时候.其实完全把方法混洗的代码抽出来成为一个工具.如下:
Swizzlling.png

这种写法稍微要严谨一点
说一说Method,SEL,IMP之间的关系,比较重要,我们直接来看,Method是runtime内部定义的方法


Method定义.png

网上找了几张图,分析一下具体的实现过程

第一步.png 第二步.png
  • 3.动态添加方法(消息转发)
    一般处理的就是当类中没有定义方法,而调用了会包方法找不到的错误.可以通过消息转发搞定这个异常.具体的消息转发可以参考这里.来个图吧.
消息转发流程.png

.在实际应用中一般就走到第一步就OK了.

实际应用.png
  • 4.字典转模型
    字典转模型我一般比较少用,
    这段代码已经用过好多次,josnModel里面已经写烂了.我也只是一名搬运工
 + (instancetype)modelWithDict:(NSDictionary *)dict
    {
        // 思路:遍历模型中所有属性-》使用运行时
        
        // 0.创建对应的对象
        id objc = [[self alloc] init];
        
        // 1.利用runtime给对象中的成员属性赋值
        
        // class_copyIvarList:获取类中的所有成员属性
        // Ivar:成员属性的意思
        // 第一个参数:表示获取哪个类中的成员属性
        // 第二个参数:表示这个类有多少成员属性,传入一个Int变量地址,会自动给这个变量赋值
        // 返回值Ivar *:指的是一个ivar数组,会把所有成员属性放在一个数组中,通过返回的数组就能全部获取到。
        /* 类似下面这种写法
         
         Ivar ivar;
         Ivar ivar1;
         Ivar ivar2;
         // 定义一个ivar的数组a
         Ivar a[] = {ivar,ivar1,ivar2};
         
         // 用一个Ivar *指针指向数组第一个元素
         Ivar *ivarList = a;
         
         // 根据指针访问数组第一个元素
         ivarList[0];
         
         */
        unsigned int count;
        
        // 获取类中的所有成员属性
        Ivar *ivarList = class_copyIvarList(self, &count);
        
        for (int i = 0; i < count; i++) {
            // 根据角标,从数组取出对应的成员属性
            Ivar ivar = ivarList[i];
            
            // 获取成员属性名
            NSString *name = [NSString stringWithUTF8String:ivar_getName(ivar)];
            
            // 处理成员属性名->字典中的key
            // 从第一个角标开始截取
            NSString *key = [name substringFromIndex:1];
            
            // 根据成员属性名去字典中查找对应的value
            id value = dict[key];
            
            // 二级转换:如果字典中还有字典,也需要把对应的字典转换成模型
            // 判断下value是否是字典
            if ([value isKindOfClass:[NSDictionary class]]) {
                // 字典转模型
                // 获取模型的类对象,调用modelWithDict
                // 模型的类名已知,就是成员属性的类型
                
                // 获取成员属性类型
                NSString *type = [NSString stringWithUTF8String:ivar_getTypeEncoding(ivar)];
                // 生成的是这种@"@\"User\"" 类型 -》 @"User"  在OC字符串中 \" -> ",\是转义的意思,不占用字符
                // 裁剪类型字符串
                NSRange range = [type rangeOfString:@"\""];
                
                type = [type substringFromIndex:range.location + range.length];
                
                range = [type rangeOfString:@"\""];
                
                // 裁剪到哪个角标,不包括当前角标
                type = [type substringToIndex:range.location];
                
                
                // 根据字符串类名生成类对象
                Class modelClass = NSClassFromString(type);
                
                
                if (modelClass) { // 有对应的模型才需要转
                    
                    // 把字典转模型
                    value  =  [modelClass modelWithDict:value];
                }
                
                
            }
            
            // 三级转换:NSArray中也是字典,把数组中的字典转换成模型.
            // 判断值是否是数组
            if ([value isKindOfClass:[NSArray class]]) {
                // 判断对应类有没有实现字典数组转模型数组的协议
                if ([self respondsToSelector:@selector(arrayContainModelClass)]) {
                    
                    // 转换成id类型,就能调用任何对象的方法
                    id idSelf = self;
                    
                    // 获取数组中字典对应的模型
                    NSString *type =  [idSelf arrayContainModelClass][key];
                    
                    // 生成模型
                    Class classModel = NSClassFromString(type);
                    NSMutableArray *arrM = [NSMutableArray array];
                    // 遍历字典数组,生成模型数组
                    for (NSDictionary *dict in value) {
                        // 字典转模型
                        id model =  [classModel modelWithDict:dict];
                        [arrM addObject:model];
                    }
                    
                    // 把模型数组赋值给value
                    value = arrM;
              
                }
            }
            
            
            if (value) { // 有值,才需要给模型的属性赋值
                // 利用KVC给模型中的属性赋值
                [objc setValue:value forKey:key];
            }
            
        }
        
        return objc;
    }

### 总结
这篇简单讲了一下,runtime在开发中用到的场景.属于应用层面,下篇开始讲原理
参考链接
[快速上手Runtime](http://www.jianshu.com/p/e071206103a4)

相关文章

  • 再来看看费脑的Runtime-实用篇

    开篇 使用场景 1.给分类添加属性目前常用的两种方式,一种是显示定义定义属性关联的key,一种是直接通过方法名作为...

  • Runtime-原理

    runtime初探对象与方法的本质runtime-消息发送runtime-动态方法解析runtime-消息转发 r...

  • 绘本讲师训练营【15期】6/21阅读原创:牛津阅读树《Ice C

    15037 费尘Fay 再来介绍一本牛津阅读树Phonics系列的故事书。Phonics真的是非常实用的阅读工具,...

  • runtime-整理中

    runtime-整理中

  • 写作不要费脑

    写作不要费脑 有一位文友(丹青妙笔)说:“一天五篇,好厉害!我一天两篇都觉得费脑,只能坚持每天一篇,偶尔灵感多也就...

  • Python旋转矩阵的骚操作

    先来个自己写的,很费脑,很耗时,很暴力 再来个一行解决的 关键用到了zip可以对矩阵进行转置的操作

  • 【健身日记】动感单车

    (文/叔丁) 去欧洲的飞机上要消磨8小时时光,想挑选几个电影看看。戏剧太费脑,动作太费眼,浪漫太费情,家庭太费神,...

  • 回顾我们收益

    我们先看看总体前面几篇文章: 我们先看看第一篇的内容: 确实那个时候适合建仓!!我再来看看第二篇: 第一篇建仓,算...

  • LMS的正确打开方式-Learndash (II)

    上篇浅谈了一下Learndash作为线上学习系统开发这个宝藏的实用性。今天我们再来一起看看Learndash最大的...

  • 如何学习——两年教师经历教会我的

    这两天看到worfcon的一篇推送,讲费曼技巧。 费曼技巧是种非常实用的方法,不管学习哪类知识都可以这个技巧来验证...

网友评论

    本文标题:再来看看费脑的Runtime-实用篇

    本文链接:https://www.haomeiwen.com/subject/visklttx.html