iOS KVC (十)模型转换

iOS KVC(一)基本了解
iOS KVC (二) 不可不知的赋值深层次原理
iOS KVC (三)不可不知的取值深层次原理
iOS KVC (四)keyPath的深度解析
iOS KVC (五)KVC几种典型的异常处理
iOS KVC (六) KVC容器类及深层次原理
iOS KVC(七) KVC正确性的验证
iOS KVC (八) KVC几种常见应用
iOS KVC (九) KVC模型转化(1) 模型打印 description, debugDescription
iOS KVC (十)模型转换(2)模型转换

本章主要讲单层次的模型转换 后期学习任务归结到 YYModel ,JsonModel,MJExtension的源码分析是会不发 此章也是模型转换的基础。

1传统设置方法

直接上代码
1.Person.h

#import <Foundation/Foundation.h>

@interface Person : NSObject

@property (nonatomic,strong)NSString *name;
@property (nonatomic,assign)int age;

+ (instancetype)personWithDict:(NSDictionary *)dict;
- (instancetype)initWithDict:(NSDictionary *)dict;

@end

2.Person.m

#import "Person.h"
#import <objc/runtime.h>
@implementation Person

- (NSString *)description{
    NSMutableDictionary *dic = [NSMutableDictionary dictionary];
    //得到当前class的所有属性
    uint count;
    objc_property_t *properties = class_copyPropertyList([self class], &count);
    for (int i = 0; i<count; i++) {
        objc_property_t property = properties[i];
        NSString *name = @(property_getName(property));
        id value = [self valueForKey:name]?:[NSNull null];//默认值不可为为nil的字符串
        [dic setObject:value forKey:name];
    }
    free(properties);
    return [NSString stringWithFormat:@"%@:%@",[self class],dic];
}

+ (instancetype)personWithDict:(NSDictionary *)dict {
    return [[self alloc] initWithDict:dict];
}

- (instancetype)initWithDict:(NSDictionary *)dict {
    self = [super init];
    if (self) {
        // 方法 1,直接设置,基本数据类型需要转换
        _name = dict[@"name"];
        _age = [dict[@"age"] intValue];
    }
    return self;
}

3.实例调用

#import "ViewController.h"

#import "Person.h"

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    NSDictionary *dic = @{
                          @"name":@"小明",
                          @"age":@10,
                          @"address":@"河南"
                          };
    Person *p = [Person personWithDict:dic];
    NSLog(@"%@",p);
}


- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

4.打印数据

018-05-18 20:50:38.774764+0700 KVCDemo[4798:382355] Person:{
    age = 10;
    name = "\U5c0f\U660e";
}

5.总结:
无论字典中有没有包含模型的字段,都不会导致崩溃,包含赋值,不包含不赋值,多不退,少不补。

2KVC基础设置方法

1.Person.h

#import <Foundation/Foundation.h>

@interface Person : NSObject

@property (nonatomic,copy)NSString * _Nullable name;
@property (nonatomic,assign)int age;
@property (nonnull,copy)NSString *adress;

+ (instancetype _Nullable )personWithDict:(NSDictionary *_Nullable)dict;
- (instancetype _Nullable )initWithDict:(NSDictionary *_Nullable)dict;

@end

2.Person.m

#import "Person.h"
#import <objc/runtime.h>
@implementation Person

- (NSString *)description{
    NSMutableDictionary *dic = [NSMutableDictionary dictionary];
    //得到当前class的所有属性
    uint count;
    objc_property_t *properties = class_copyPropertyList([self class], &count);
    for (int i = 0; i<count; i++) {
        objc_property_t property = properties[i];
        NSString *key = @(property_getName(property));
        id value = [self valueForKey:key]?:[NSNull null];//此处不能为nil 因为字典中尽量不要出现nil 应该为[NSNull null]
        [dic setObject:value forKey:key];
    }
    free(properties);
    return [NSString stringWithFormat:@"%@:%@",[self class],dic];
}



+ (instancetype)personWithDict:(NSDictionary *)dict {
    return [[self alloc] initWithDict:dict];
}

- (instancetype)initWithDict:(NSDictionary *)dict {
    self = [super init];
    if (self) {
        [self setValue:dict[@"name"] forKey:@"name"];
        [self setValue:dict[@"age"] forKey:@"age"];
        [self setValue:dict[@"adress"] forKey:@"adress"];
        
    }
    return self;
}

- (void)setValue:(id)value forUndefinedKey:(NSString *)key{
    NSLog(@"不存在Key:%@",key);
}

- (void)setNilValueForKey:(NSString *)key{
    NSLog(@"属性值不能为nil");
}
@end

3.调用

#import "ViewController.h"
#import "Person.h"
@interface ViewController ()
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    NSDictionary *dic = @{
                          @"name":[NSNull null],
                          @"adress":@"河南",
                          @"age":@10
                          };
    Person *p = [Person personWithDict:dic];
    NSLog(@"%@",p);
}

4.打印数据:

2018-05-18 22:38:44.749136+0700 KVCDemo[6297:464723] Person:{
    adress = "\U6cb3\U5357";
    age = 10;
    name = "<null>";
}

5.总结:

1 - (void)setValue:(id)value forUndefinedKey:(NSString *)key
模型中不存在这个key会调用此方法。
2- (void)setNilValueForKey:(NSString *)key
当模型中的整形不存在时调用此方法。 并且如果整形不存在系统会将0赋予这个整型的字段。
3.这两个方法是必须执行的,因为如果不执行,如果存在不存在的key 或者模型的整形字段不存在,都会导致程序的崩溃。

3遍历字典

1.Person.h

#import <Foundation/Foundation.h>

@interface Person : NSObject

@property (nonatomic,copy)NSString * _Nullable name;
@property (nonatomic,assign)int age;
@property (nonnull,copy)NSString *adress;


+ (instancetype _Nullable )personWithDict:(NSDictionary *_Nullable)dict;
- (instancetype _Nullable )initWithDict:(NSDictionary *_Nullable)dict;

@end

2.Person.m

#import "Person.h"
#import <objc/runtime.h>
@implementation Person

- (NSString *)description{
    NSMutableDictionary *dic = [NSMutableDictionary dictionary];
    //得到当前class的所有属性
    uint count;
    objc_property_t *properties = class_copyPropertyList([self class], &count);
    for (int i = 0; i<count; i++) {
        objc_property_t property = properties[i];
        NSString *key = @(property_getName(property));
        id value = [self valueForKey:key]?:[NSNull null];//此处不能为nil 因为字典中尽量不要出现nil 应该为[NSNull null]
        [dic setObject:value forKey:key];
    }
    free(properties);
    return [NSString stringWithFormat:@"%@:%@",[self class],dic];
}



+ (instancetype)personWithDict:(NSDictionary *)dict {
    return [[self alloc] initWithDict:dict];
}

- (instancetype)initWithDict:(NSDictionary *)dict {
    self = [super init];
    if (self) {
        for (NSString *key in dict) {
            id value = dict[key];
            [self setValue:value forKey:key];
        }
        
    }
    return self;
}

- (void)setValue:(id)value forUndefinedKey:(NSString *)key{
    NSLog(@"不存在Key:%@",key);
}

- (void)setNilValueForKey:(NSString *)key{
    NSLog(@"属性值不能为nil");
}
- (BOOL)validatePersonName:(id *)value error:(out NSError * _Nullable __autoreleasing *)outError
{
    NSString *name = *value;
    if ([name isEqualToString:@"小明"]) {
        return YES;
    }
    return NO;
}

3.调用

#import "ViewController.h"
#import "Person.h"

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    NSDictionary *dic = @{
                          @"name":[NSNull null],
                          @"adress":@"河南",
                          @"age":@10
                          };
    Person *p = [Person personWithDict:dic];
    NSLog(@"%@",p);
}

4.打印数据:

2018-05-19 16:17:55.638697+0700 KVCDemo[7364:534839] Person:{
    adress = "\U6cb3\U5357";
    age = 10;
    name = "<null>";
}

5.总结:
写到此刻我已经无话可说了,只是一种方式。

4. setValuesForKeysWithDictionary

1.Person.h

#import <Foundation/Foundation.h>

@interface Person : NSObject

@property (nonatomic,copy)NSString * _Nullable name;
@property (nonatomic,assign)int age;
@property (nonnull,copy)NSString *adress;


+ (instancetype _Nullable )personWithDict:(NSDictionary *_Nullable)dict;
- (instancetype _Nullable )initWithDict:(NSDictionary *_Nullable)dict;

@end

2.Person.m

#import "Person.h"
#import <objc/runtime.h>
@implementation Person

- (NSString *)description{
    NSMutableDictionary *dic = [NSMutableDictionary dictionary];
    //得到当前class的所有属性
    uint count;
    objc_property_t *properties = class_copyPropertyList([self class], &count);
    for (int i = 0; i<count; i++) {
        objc_property_t property = properties[i];
        NSString *key = @(property_getName(property));
        id value = [self valueForKey:key]?:[NSNull null];//此处不能为nil 因为字典中尽量不要出现nil 应该为[NSNull null]
        [dic setObject:value forKey:key];
    }
    free(properties);
    return [NSString stringWithFormat:@"%@:%@",[self class],dic];
}



+ (instancetype)personWithDict:(NSDictionary *)dict {
    return [[self alloc] initWithDict:dict];
}

- (instancetype)initWithDict:(NSDictionary *)dict {
    self = [super init];
    if (self) {
        [self setValuesForKeysWithDictionary:dict];
    }
    return self;
}

- (void)setValue:(id)value forUndefinedKey:(NSString *)key{
    NSLog(@"不存在Key:%@",key);
}

- (void)setNilValueForKey:(NSString *)key{
    NSLog(@"属性值不能为nil");
}
- (BOOL)validatePersonName:(id *)value error:(out NSError * _Nullable __autoreleasing *)outError
{
    NSString *name = *value;
    if ([name isEqualToString:@"小明"]) {
        return YES;
    }
    return NO;
}

3.调用

#import "ViewController.h"
#import "Person.h"

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    NSDictionary *dic = @{
                          @"name":[NSNull null],
                          @"adress":@"河南",
                          @"age":@10
                          };
    Person *p = [Person personWithDict:dic];
    NSLog(@"%@",p);
}

4.打印数据:

2018-05-19 16:29:15.202777+0700 KVCDemo[7492:542825] Person:{
    adress = "\U6cb3\U5357";
    age = 10;
    name = "<null>";
}

5.总结:
此方法等同于遍历字典,设置数据,等同于方法3

分享几篇关于模型多层转化的文章,希望对大家有所帮助。
iOS - 教你一步一步实现自己的字典转模型库
iOS开发·runtime+KVC实现多层字典模型转换(多层数据:模型嵌套模型,模型嵌套数组,数组嵌套模型)

到此为止关于KVC的基础知识就已经完结了,希望对你有所帮助。接下分享KVO。

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

推荐阅读更多精彩内容

  • 1.ios高性能编程 (1).内层 最小的内层平均值和峰值(2).耗电量 高效的算法和数据结构(3).初始化时...
    欧辰_OSR阅读 29,321评论 8 265
  • 为加大社会保险宣传力度,推进城镇企业职工养老保险制度健康稳步运行,26日,绥滨县社保局开展了以“社会保险,...
    丁小孩阅读 352评论 0 0
  • 曾经的我有段时间非常迷恋奇葩说。被里面的辩论深深吸引,我常常感叹,他们真的是为辩论而生,她们的妙语连珠,精彩纷呈,...
    深夜灵感阅读 186评论 0 0
  • 朋友圈充斥着每个朋友对2017的美好回忆。 而对我来说,这是极度不平凡的一年。 2017,1月7日回到汕头,决定要...
    Oh_930f阅读 155评论 0 0
  • 我爱无名的罪 大地的根深埋土壤 钻透人世间的悲欢离合 我也爱世俗的眼 天空的鱼是彻底的蓝 自由地遨翔是终生的命 我...
    伍月的晴空阅读 231评论 8 8