KVC的相关了解

KVC研究

  • setvalue forkey
  • setvalue forUndefinedkey

转自:KVC与setValue:forUndefinedKey:方法

在实际开发及应用过程中,经常会遇到通过外部数据构造的字典的键与自定义数据模型类中属性的名称或是个数不一致的情况。
例如:从外部获得JSON格式的数据包含5个键,如下所示:

{
    "cityname" : "beijing",
    "state1" : "0",
    "state2" : "1",
    "tem1" : "25",
    "tem2" : "14",
}

而与之对应的模型只包含3个属性:

** 城市名 */
@property (copy, nonatomic) NSString *cityname;

/** 最低温度 */
@property (copy, nonatomic) NSNumber *tem1;

/** 最高温度 */
@property (copy, nonatomic) NSNumber *tem2;


在VC中
- (void)viewDidLoad {
    [super viewDidLoad];
    
    // 读取JSON格式的外部数据
    NSURL *url = [[NSBundle mainBundle] URLForResource:@"weather" withExtension:@"json"];
    NSData *data = [NSData dataWithContentsOfURL:url];
    NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:NULL];

    // 数据模型实例
    Weather *w = [Weather weatherWithDictionary:dict];
    NSLog(@"%@", w);
}

模型类Weather.h:
#import <Foundation/Foundation.h>

@interface Weather : NSObject

/** 城市名 */
@property (copy, nonatomic) NSString *cityname;

/** 最低温度 */
@property (copy, nonatomic) NSNumber *tem1;

/** 最高温度 */
@property (copy, nonatomic) NSNumber *tem2;

- (instancetype)initWithDictionary:(NSDictionary *)dict;
+ (instancetype)weatherWithDictionary:(NSDictionary *)dict;

@end

#import "Weather.h"

@implementation Weather

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

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


- (NSString *)description {
    return [NSString stringWithFormat:@"[cityname, tem1, tem2] = [%@, %@, %@]", self.cityname, self.tem1, self.tem2];
}

@end

此时,如果运行程序,会报告以下错误信息:

*** Terminating app due to uncaught exception ‘NSUnknownKeyException’, reason: ‘[ setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key state1.’
*** First throw call stack:
(
0 CoreFoundation 0x000000010e158c65 __exceptionPreprocess + 165
1 libobjc.A.dylib 0x000000010ddefbb7 objc_exception_throw + 45
2 CoreFoundation 0x000000010e1588a9 -[NSException raise] + 9
3 Foundation 0x000000010d984b53 -[NSObject(NSKeyValueCoding) setValue:forKey:] + 259
4 Foundation 0x000000010d9c6fad -[NSObject(NSKeyValueCoding) setValuesForKeysWithDictionary:] + 261
5 2015-05-05-setValueforUndefinedKey 0x000000010d8b94bd -[Weather initWithDictionary:] + 141
6 2015-05-05-setValueforUndefinedKey 0x000000010d8b9557 +[Weather weatherWithDictionary:] + 87
7 2015-05-05-setValueforUndefinedKey 0x000000010d8b9925 -[ViewController viewDidLoad] + 277
8 UIKit 0x000000010e683210 -[UIViewController loadViewIfRequired] + 738
9 UIKit 0x000000010e68340e -[UIViewController view] + 27
10 UIKit 0x000000010e59e2c9 -[UIWindow addRootViewControllerViewIfPossible] + 58
11 UIKit 0x000000010e59e68f -[UIWindow _setHidden:forced:] + 247
12 UIKit 0x000000011bb4a175 -[UIWindowAccessibility _orderFrontWithoutMakingKey] + 68
13 UIKit 0x000000010e5aae21 -[UIWindow makeKeyAndVisible] + 42
14 UIKit 0x000000010e54e457 -[UIApplication _callInitializationDelegatesForMainScene:transitionContext:] + 2732
15 UIKit 0x000000010e5511de -[UIApplication _runWithMainScene:transitionContext:completion:] + 1349
16 UIKit 0x000000010e5500d5 -[UIApplication workspaceDidEndTransaction:] + 179
17 FrontBoardServices 0x0000000110d575e5 __31-[FBSSerialQueue performAsync:]_block_invoke_2 + 21
18 CoreFoundation 0x000000010e08c41c CFRUNLOOP_IS_CALLING_OUT_TO_A_BLOCK + 12
19 CoreFoundation 0x000000010e082165 __CFRunLoopDoBlocks + 341
20 CoreFoundation 0x000000010e081f25 __CFRunLoopRun + 2389
21 CoreFoundation 0x000000010e081366 CFRunLoopRunSpecific + 470
22 UIKit 0x000000010e54fb42 -[UIApplication _run] + 413
23 UIKit 0x000000010e552900 UIApplicationMain + 1282
24 2015-05-05-setValueforUndefinedKey 0x000000010d8b9c7f main + 111
25 libdyld.dylib 0x0000000110727145 start + 1
26 ??? 0x0000000000000001 0x0 + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException

  • 当使用setValuesForKeysWithDictionary:方法时,对于数据模型中缺少的、不能与任何键配对的属性的时候,系统会自动调用setValue:forUndefinedKey:这个方法,该方法默认的实现会引发一个NSUndefinedKeyExceptiony异常。-》就是不手动重写,靠系统自动调用的话,会报异常
  • 如果想要程序在运行过程中不引发任何异常信息且正常工作,可以让数据模型类重写setValue:forUndefinedKey:方法以覆盖默认实现,而且可以通过这个方法的两个参数获得无法配对键值。
  • 比如后台返回json里面有id键值。而我们自定义模型里面肯定是定义一个属性比如keyid来接收这个id键值,就可以在自定义模型里面重写setValue:forUndefinedKey:这个方法
- (void)setValue:(id)value forUndefinedKey:(NSString *)key
{
    if([key isEqualToString:@"id"]){
        self.keyid = [value intValue];
    }
}

区分kvc与字典API

setObject:ForKey: 是NSMutableDictionary特有的;
setValue:ForKey:是KVC的主要方法
setobject中的key和value可以为除了nil外的任何对象
setValue中的key只能为字符串 value可以为nil也可以为空对象[NSNull null]以及全部对象
  • 总结两者的区别:
setObject:forked:中object是不能够为nil的,不然会报错。
setValue:forKey:中value能够为nil,但是当value为nil的时候,会自动调用removeObject:forKey方法
setValue:forKey:中key的参数只能够是NSString类型,而setObject:forKey:的可以是任何类型

注意:setObject:forKey:对象不能存放nil要与下面的这种情况区分:
[imageDictionary setObject:[NSNullnull] forKey:indexNumber];
[NSNull null]表示的是一个空对象,并不是nil,注意这点

setObject:forKey:中Key是NSNumber对象的时候,如下:
[imageDictionary setObject:obj forKey:[NSNumber numberWithInt:10]];
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值