XZ_iOS之Runtime使用运行时实现字典转模型和关联对象_运行时添加字典-程序员宅基地

技术标签: 字典转模型  运行时  objc_getsetAssociate  runtime  关联对象  iOS  

使用运行时实现字典转模型和关联对象objc_get/setAssociatedObject()

创建一个类Person,重写它的description方法,打印出它的属性值。

XZPerson.m
@implementation XZPerson

- ( NSString *)description {
    NSArray *keys = @[ @"name" , @"age" , @"weight" , @"sex" ] ;
   
    return [ self dictionaryWithValuesForKeys :keys]. description ;
}
@end

NSObject+XZRuntime.h
#import <Foundation/Foundation.h>

@interface NSObject (XZRuntime)
// 获取类的属性列表
// @return 类的属性列表数组
+ ( NSArray *)xz_objcProperties;

// 给定一个字典,创建 self 类对应的对象
// @param dict 字典   @return 对象
+ ( instancetype )xz_objWithDic:( NSDictionary *)dict;
@end

NSObject+XZRuntime.m
#import "NSObject+XZRuntime.h"
#import <objc/runtime.h>

@implementation NSObject (XZRuntime)

// 所有字典转模型框架的核心算法 // 运行时字典转模型的基本方法的实现
+ ( instancetype )xz_objWithDic:( NSDictionary *)dict {
    // 实例化对象
    id object = [[ self alloc ] init ];
   
    // 使用字典,设置对象信息
    // 1> 获得 self 的属性列表
    NSArray *proList = [ self xz_objcProperties ];
    // 2> 遍历字典
    [dict enumerateKeysAndObjectsUsingBlock :^( id   _Nonnull key, id   _Nonnull obj, BOOL * _Nonnull stop) {
        NSLog ( @"key %@ ---- value %@" ,key,obj);
        // 3> 判断 key 是否存在 proList
        if ([proList containsObject :key]) {
            // 说明属性存在,可以使用 ‘KVC’ 设置数值
            [object setValue :obj forKey :key];
        }
    }];
   
    return object;
}

const char *kPropertiesListKey = "CZPropertiesListKey" ;
+ ( NSArray *)xz_objcProperties {
    // 因为属性列表在运行的过程中不会改变,所以使用运行时关联对象,提高效率
    // ①、从 关联对象 中获取对象属性,如果有,直接返回!
    /**
     获取关联对象 -- 动态添加的属性
     参数 1 :对象 :self  参数 2 :动态属性的 key
     返回值:动态添加的 属性值 ’ id
     */
    NSArray *ptyList = objc_getAssociatedObject ( self , kPropertiesListKey );
    if (ptyList != nil ) {
        return ptyList;
    }
   
    // 使用运行时获取对象的属性数组
    // class_copyIvarList  Ivar 成员变量
    // class_copyPropertyList  Property 属性
    // class_copyMethodList  Method 方法
    // class_copyProtocolList  Protocol 协议
    // 参数一:要获取的类 参数二:类属性的个数指针
    // 返回值:所有属性的 ' 数组 ' C 语言中,数组的名字,就是指向第一个元素的地址
    unsigned int outCount = 0 ;
    // 调用运行时方法,取得类的属性列表
    objc_property_t *proList = class_copyPropertyList ([ self class ], &outCount);
    NSLog ( @" 属性列表的数量 %d" ,outCount);
   
    NSMutableArray *array = [ NSMutableArray array ];
    // 遍历所有的属性
    for ( unsigned int i = 0 ; i < outCount; i++) {
        //1. 从数组中取得属性 C 语言的结构体指针,通常不需要 '*'
        objc_property_t pty = proList[i];
       
        // 2. pty 中获得属性的名称
        const char *cName = property_getName (pty);
        // C 语言字符串转化成 OC 字符串
        NSString *name = [ NSString stringWithCString :cName encoding : NSUTF8StringEncoding ];
        // 3. 属性名称添加到数组
        [array addObject :name];
    }
   
    // retain/create/copy 需要 release ,点击 option + click 查看
    // 释放数组
    free (proList);
   
    // ②、到此为止,对象的属性数组已经获取完毕,利用关联对象,动态添加属性
    /**
     参数
     1. 对象 self [OC class 也是一个特殊的对象 ]
     2. 动态添加的属性的 key ,获取值的时候也使用
     3. 动态添加的属性值
     4. 对象的引用关系
     */
    objc_setAssociatedObject ( self , kPropertiesListKey , array. copy , OBJC_ASSOCIATION_RETAIN_NONATOMIC );
    return array. copy ;
}

@end

XZRunTimeController.m
// 字典转模型
    XZPerson *person = [ XZPerson xz_objWithDic : @{
                                                 @"name" : @"zhangsan" ,
                                                 @"age" : @18 ,
                                                 @"sex" : @"female" ,
                                                 @"height" : @1.8 ,
                                                 @"weight" : @100 ,
                                                 } ];

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/understand_XZ/article/details/76316554

智能推荐

在Watir中调用JavaScript脚本_watir执行脚本-程序员宅基地

文章浏览阅读3.9k次。如何在Watir中调用JavaScript脚本?下面的脚本实现了此功能,主要原理是通过IE访问Document,再访问parentWindow,最终还是由IE在执行JavaScript脚本: require watir#定义调用JS的类方法class Watir::IE def run_script(js) ie.Document.parentWindow.execS_watir执行脚本

为什么不能使用Thread.stop()方法?_禁止使用thread.stop()来终止线程-程序员宅基地

文章浏览阅读2.1k次。从SUN的官方文档可以得知,调用Thread.stop()方法是不安全的,这是因为当调用Thread.stop()方法时,会发生下面两件事:1. 即刻抛出ThreadDeath异常,在线程的run()方法内,任何一点都有可能抛出ThreadDeath Error,包括在catch或finally语句中。2. 释放该线程所持有的所有的锁 当线程抛出ThreadDeath异常时,会导致_禁止使用thread.stop()来终止线程

神秘魔术动作能量冲击波特效音效Arcane Forces第一套 MAGIC - ARCANE FORCES DESIGNED_magic – arcane forces-程序员宅基地

文章浏览阅读222次。神秘魔术动作能量冲击波特效音效Arcane Forces第一套 MAGIC - ARCANE FORCES DESIGNED原文地址:https://www.aeziyuan.com/t-20646.html文件格式:.WAV文件大小:1.26 GB(解压包大小)文件数量:124音频码率:96kHz, 24-bit音效适用于任何音/视频后期编辑软件,直接导入即可使用包含:酸,奥术,障壁,呼吸,增益,诅咒,减伤,神圣,电,能量,火,玻璃,冰,冲击,光,液体,金属,加工,抛射,隆隆声,序,召唤,._magic – arcane forces

commons-io工具包的基本使用_ioutils.tobytearray-程序员宅基地

文章浏览阅读4w次,点赞57次,收藏304次。目录一、工具类IOUtils的使用:FileUtils的使用:FilenameUtils的使用FileSystemUtils的使用:二、输入、输出三、Filters过滤器四、Comparators比较器五、Monitor文件监控简介:java io操作是开发中比较常用的技术,但是如果每次都使用原生的IO流来操作会显得比较繁琐。Common IO 是一..._ioutils.tobytearray

平面射影_坐标平面射影是什么-程序员宅基地

文章浏览阅读1.9k次。欧氏坐标(x,y)-&gt;-&gt; 平面上所有无穷远点所构成的集合称为无穷远直线。 射影平面:由欧氏平面与无穷远直线的并集所形成的扩展平面称为射影平面,有时也称为二维射影空间。向量的反对称矩阵定义为的叉积为矩阵具有如下性质:对偶命题:在射影平面内,点和线是一对互为对偶元素。在包含"点"和“线”元素的命题中,如果将两个元素的角色互换,则对应的命题也成立,并称它们是一对互为对偶命题。,二维向量称为..._坐标平面射影是什么

详解HTML的a标签(超链接标签)-程序员宅基地

文章浏览阅读1k次。原文  简书原文:https://www.jianshu.com/p/d6a2499db73b大纲  1、什么是<a>标签  2、<a>标签的几个重要属性  3、a标签的运行机制  4、a标签常用的协议  5、超链接标签的样式问题——a标签的伪类选择器的书写顺序1、什么是<a>标签  <a> 标签定义超链接,用于从一张页面链接到另..._超链

随便推点

Jupyter Notebook如何调试?JupyterLab作为DeBug调试工具及调试教程_jupyterlab怎么debug-程序员宅基地

文章浏览阅读2.9w次,点赞30次,收藏107次。引言xeus-python是2020年新出的Jupyter notebook调试工具,参考机器之心的文章首款 Jupyter 官方可视化 Debug 工具,JupyterLab 未来可默认支持 Debug安装过程安装JupyterLab 前端插件jupyter labextension install @jupyterlab/debugger安装xeus-python作为后端kernelconda install xeus-python -c conda-forge调试教程只要装好前端与_jupyterlab怎么debug

如何将xml转换为json_xml转json-程序员宅基地

文章浏览阅读3.8k次。<dependency> <groupId>org.json</groupId> <artifactId>json</artifactId> <version>20160807</version> </dependency>导入 json-20160807.jar jar包 直接调用 XML.toJSONObject(“xml内容”) 就可以把XML._xml转json

TCP 的那些事 | TCP报文格式解析_.tcp文件是图片吗-程序员宅基地

文章浏览阅读1.3k次。TCP(Transmission Control Protocol 传输控制协议)提供一种面向连接的、可靠的字节流服务。面向连接意味着两个使用TCP的应用(通常是一个客户和一个服务器)在彼此交换数据之前必须先建立一个TCP连接。TCP在网络ISO的七层模型中的第四层---Transport层,在TCP/IP协议中的第三层---传输层。TCP通过下列方式来提供可靠性:1. 应用数据被分..._.tcp文件是图片吗

python——stack()和unstack()用法_unstack函数-程序员宅基地

文章浏览阅读1.2w次,点赞12次,收藏54次。在学习python的过程中遇到了这两个函数,讲讲学习的心得_unstack函数

AOP与OOP有什么区别,谈谈AOP的原理是什么,大厂Android高级面试题汇总解答-程序员宅基地

文章浏览阅读521次,点赞25次,收藏11次。包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频**

推荐文章

热门文章

相关标签