【iOS问题】字典转模型,属性个数不匹配问题

时间:2024-12-08 15:05:32

一、字典转模型的键值对与模型属性不匹配问题

  1. 字典的键个数 < 模型的属性个数 (key 能与模型的属性匹配)

    1> .KVO 方式:

      - setValuesForKeysWithDictionary:

    2> for循环的方式,一一赋值

  2.字典的键个数 = 模型的属性个数 (key 能与模型的属性匹配)

    同1。

  3.字典的个数 > 模型的属性个数 (模型的属性为字典key 的其中一部分)

     一共有三种解决方式

二、解决办法:

  建立一个GXApp的模型,申明两个属性: name(名称)  details(详细信息),在类方法中是直接使用

  【iOS问题】字典转模型,属性个数不匹配问题

  

  【iOS问题】字典转模型,属性个数不匹配问题

  

  在控制器中使用:

  【iOS问题】字典转模型,属性个数不匹配问题

  直接运行:

    Terminating app due to uncaught exception 'NSUnknownKeyException',

  reason: '[<GXApp 0x7ff1a8d41790> setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key version .'

解决办法一:

  在类方法中,一个个属性赋值

  

 //
 //  GXApp.m
 //  B01-字典转模型的属性不匹配问题
 //
 //  Created by gxiangzi on 15/8/25.
 //  Copyright (c) 2015年 hqu. All rights reserved.
 //

 #import "GXApp.h"

 @implementation GXApp

 + (instancetype)appWithDict:(NSDictionary*)dict
 {
     GXApp* app = [[GXApp alloc] init];

     // 利用数组存储 模型的属性
     NSArray* parameters = @[ @"name", @"details" ];
     // 遍历字典,判断模型是否有该属性
     [parameters enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL* stop)
     {
         if (dict[obj])
         {
             [app setValue:dict[obj] forKey:obj];
         }
     }];

     return app;
 }

 @end

缺点: 该种方式对极少数属性相对简单,但是扩展性不高。

解决办法二

  运行是机制,在运行时,判断模型的属性,然后赋值

  

 //
 //  GXApp.m
 //  B01-字典转模型的属性不匹配问题
 //
 //  Created by gxiangzi on 15/8/25.
 //  Copyright (c) 2015年 hqu. All rights reserved.
 //

 #import "GXApp.h"
 #import <objc/runtime.h>

 @implementation GXApp

 + (instancetype)appWithDict:(NSDictionary *)dict
 {
     GXApp *app = [[GXApp alloc] init];

     NSArray *array = [app getProperties];

     // 根据属性的值,去数据字典中取对应的值
     [array enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
         // key 属性值.
         NSString *key = obj;

         if (dict[key]) {

             [app setValue:dict[key] forKey:key];
         }

     }];

     return app;
 }

 // 动态的获取某一个类的属性.
 - (NSArray *)getProperties
 {
     unsigned int count;

     // 获取一个类中的属性
     objc_property_t *properties = class_copyPropertyList(self.class, &count);

     NSMutableArray *array = [NSMutableArray array];

     // 遍历类中的属性,将每一个属性值都转换成 OC 的字符串
     ; i < count; i++) {

         // pro 依然是 C 语言的数据类型
         objc_property_t pro = properties[i];

         // 指向C 语言字符串一个指针.
         const char *name = property_getName(pro);

         NSString *property = [[NSString alloc] initWithUTF8String:name];

         [array addObject:property];
     }

     return array;
 }

 @end

缺点:运行时代码,C语言代码,代码不易记住

解决办法三、

   重写 - setValuesForKeysWithDictionary:

  

//
//  GXApp.m
//  B01-字典转模型的属性不匹配问题
//
//  Created by gxiangzi on 15/8/25.
//  Copyright (c) 2015年 hqu. All rights reserved.
//

#import "GXApp.h"

@implementation GXApp

+(instancetype)appWithDict:(NSDictionary *)dict
{
    GXApp *app = [[GXApp alloc] init];

    [app setValuesForKeysWithDictionary:dict];

    return app;
}

- (void)setValue:(id)value forUndefinedKey:(NSString *)key
{
    // do nothing
}

@end

解释:  

  官方解释:

  - (void)setValue:(id)value forUndefinedKey:(NSString *)key;

Given that an invocation of -setValue:forKey: would be unable to set the keyed value because the type of the parameter of the corresponding accessor method is an NSNumber scalar type or NSValue structure type but the value is nil, set the keyed value using some other mechanism. The default implementation of this method raises an NSInvalidArgumentException. You can override it to map nil values to something meaningful in the context of your application.

当利用kvo赋值的适合,如果键值不匹配,就会报一个 NSInvalidArgumentException 异常,可以重写这个方法可以解决