• 使用Runtime的objc_msgSend实现模型和字典的互转


    一、介绍

    模型转字典,字典转模型,这是开发中最基本的功能。系统类中提供了一个setValuesForKeysWithDictionary方法来实现字典转模型,至于模型转字典,这个就需要使用runtime来实现了。其实字典和模型的互转可以完全使用运行时runtime来实现。典型的第三方有MJExtension和YYModel。现在我就来借助runtime的思想来进行大致的实现。

    二、思路

    • 字典转模型
      • 遍历key
      • objc_msgSendkey发送消息
    • 模型转字典
      • class_copyPropertyList获取属性列表properties
      • 遍历properties,获取属性名name
      • objc_msgSend对name发送消息,设置value
      • 存入dic并返回

      

    三、示例

    person.h

    //
    //  Person.h
    //  运行时
    //
    //  Created by 夏远全 on 2019/10/11.
    //  Copyright © 2019 北京华樾教育科技有限公司. All rights reserved.
    //
    
    #import <Foundation/Foundation.h>
    
    NS_ASSUME_NONNULL_BEGIN
    
    @interface Person : NSObject
    @property (nonatomic,   copy) NSString *age;
    @property (nonatomic,   copy) NSString *name;
    
    /**
     字典转模型
     @param dic 字典
     @return 模型
     */
    -(instancetype)initWithDictionary:(NSDictionary *)dic;
    
    
    /**
     模型转字典
     @return 字典
     */
    -(NSDictionary *)convertModelToDictionary;
    
    @end
    
    NS_ASSUME_NONNULL_END

    person.m

    //
    //  Person.m
    //  运行时
    //
    //  Created by 夏远全 on 2019/10/11.
    //  Copyright © 2019 北京华樾教育科技有限公司. All rights reserved.
    //
    
    #import "Person.h"
    #import <objc/message.h>
    
    @implementation Person
    
    -(instancetype)initWithDictionary:(NSDictionary *)dic{
        
        self = [super init];
        if (self) {
            for (NSString *key in dic.allKeys) {
                //创建一个set选择器
                NSString *methodName = [NSString stringWithFormat:@"set%@:",key.capitalizedString];
                SEL selector = NSSelectorFromString(methodName);
                
                //类型异常处理
                id value = dic[key];
                if([value isKindOfClass:[NSNull class]]) continue;
                
                //发送消息
                if (!selector) continue;
                ((void (*)(id, SEL, id))objc_msgSend)(self, selector, value);
            }
        }
        return self;
    }
    
    -(NSDictionary *)convertModelToDictionary {
        
        NSMutableDictionary *dic = [NSMutableDictionary dictionary];
        
        unsigned int count;
        objc_property_t *properties = class_copyPropertyList([self class], &count);
        for (int i=0; i<count; i++) {
            objc_property_t property = properties[i];
        
            //属性名称
            const char * name = property_getName(property);
            NSString *propertyName = [NSString stringWithCString:name encoding:NSUTF8StringEncoding];
            
            //创建一个get选择器
            SEL selector = NSSelectorFromString(propertyName);
            
            //发送消息
            if (!selector) continue;
            id value = ((id (*)(id, SEL))objc_msgSend)(self, selector);
            
            //空与类型异常处理
            if(!value || [value isKindOfClass:[NSNull class]]) continue;
            
            //值存储
            [dic setValue:value forKey:propertyName];
        }
        
        //copy创建的需要释放
        free(properties);
        
        return dic;
    }
    
    @end

    四、测试

    1、dic -> model

    -(void)test_objc_DicToModel {
        
        /// 这里主要提供一个思想,全部用字符串作为字段。其他类型:对象类型/NSNumber/int/float...,需要自己再去特殊处理
        NSDictionary *dic = @{@"age":@"20",@"name":@"张三"};
        Person *person = [[Person alloc] initWithDictionary:dic];
        NSLog(@"age=%@,name=%@",person.age, person.name);
    }
    2019-10-11 18:44:47.366662+0800 运行时[84069:2402809] age=20,name=张三

    2、model -> dic

    -(void)test_objc_ModelToDic {
        
        NSDictionary *dic = @{@"age":@"20",@"name":@"张三"};
        Person *person = [[Person alloc] initWithDictionary:dic];
        NSDictionary *dic2 = [person convertModelToDictionary];
        NSLog(@"%@",dic2);
    }
    2019-10-11 18:44:47.367024+0800 运行时[84069:2402809] {
        age = 20;
        name = "U5f20U4e09";
    }
  • 相关阅读:
    system函数调用
    ubuntu设置开机默认进入界面及命令行下开启图像界面
    博客园添加目录
    [转]JavaScript自动生成博文目录导航
    博客选择: csdn博客和博客园(cnblog)
    [转]Git服务器的搭建全部功略
    Ubuntu忘记密码
    [转]android logo:内核、android开机动画
    [转]关于前置声明与C++中头文件相互包含的几点问题
    [转]while(cin>>str)输入结束符,并正确执行后续程序
  • 原文地址:https://www.cnblogs.com/XYQ-208910/p/11656113.html
Copyright © 2020-2023  润新知