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;

整个示例程序的代码如下:

控制器ViewController.m:

#import "ViewController.h"
#import "Weather.h"

@interface ViewController ()
@end

@implementation ViewController

- (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);
}

@end

模型类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

模型类Weather.m:

#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:方法以覆盖默认实现,而且可以通过这个方法的两个参数获得无法配对键值。

修改后的模型Weather.m:

#import "Weather.h"

@implementation Weather

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

// 重写setValue:forUndefinedKey:方法
- (void)setValue:(id)value forUndefinedKey:(NSString *)key {
    NSLog(@"key = %@, value = %@", key, value);
}

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

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

@end

本例中,重写setValue:forUndefinedKey:方法但不对任何未能配对的键值做任何实质性操作以忽略它们。当然,也可以在方法体中对键值进行处理。

修改完毕后,运行程序输出如下:

key = state1, value = 0
key = state2, value = 1
[cityname, tem1, tem2] = [beijing, 25, 14]
时间: 2024-11-09 01:18:19

KVC与setValue:forUndefinedKey:方法的相关文章

拷贝故事板发生的连线问题:&#39;NSUnknownKeyException&#39;, reason: &#39;[&lt;ViewController 0x7ff3da732de0&gt; setValue:forUndefinedKey:]: this class is not ……&#39;

'NSUnknownKeyException', reason: '[<ViewController 0x7ff3da732de0> setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key HeadImageView.' 出现这个的原因就是:故事板是拷贝的其他项目的,拷贝过来之后,连线也同时拷贝来,总的来说,就是因为以前的项目中某个控件已经连接到ViewController中的某个

storyboard下 setValue:forUndefinedKey:异常问题

如果没有显式的使用键值编码而出现此问题,通过查看程序基本不能发现问题所在,则有可能是storyboard中的某viewController复制于其他viewController,而相应的IBOutlet和IBAction没有进行修改,xib下同样有可能. storyboard下 setValue:forUndefinedKey:异常问题,布布扣,bubuko.com

*** Terminating app due to uncaught exception &#39;NSUnknownKeyException&#39;, reason: &#39;[ViewController &gt; setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key

*** Terminating app due to uncaught exception 'NSUnknownKeyException', reason: '[ViewController > setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key backBtn.' 第一种情况:xib文件属性输出口连接错误,IBout多连或者忘关输入口 第二种情况:引入第三方的SDK会出现错误,

setValue:forUndefinedKey

*** Terminating app due to uncaught exception 'NSUnknownKeyException', reason: '[<UIViewController 0x12b24d950> setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key Builder.' *** First throw call stack: (0x185c3c2d8 0

iOS: setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key name.

这里指抛出一个假设: 如 果你在 storyboard中, 通过 Ctrl - Drag 方式声明了一个 @property , 但你又觉得 在 Ctrl - Drag 时 ,命名的property 不理想, 这时, 你直接在 .h   和 .m 文件中 修改了这个 实例变量的名字, 这时候,编译.  结果该会怎样呢? 不妨试试吧. 这时候,会出现以下错误, 而且还会 crash. 'NSUnknownKeyException', reason: '[<NSObject 0x8c84da0>

KVC - (void)setValue:(nullable id)value forKey:(NSString *)key;

关于KVC的方法 - (void)setValue:(nullable id)value forKey:(NSString *)key; 从上面的参数类型可以看出,value必须是一个对象,可以为nil对象. 当你的属性是@property (nonatomic, assign) NSInteger testNum; 则在使用KVC时,必须将其转换成NSNumber对象,或NSString对象.但不能转换成数组等其他对象类型. [self setValue:@99 forKey:@"testNu

[&lt;DDGuessYouLIkeModel 0x7c99faf0&gt; setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key star.

出现这个提示是由于以下原因造成: 这里我用到了MJExtension将字典转为模型,但再转为模型的时候,出现这个提示,原因就是因为NSInteger后面多一个一个“*” @property (nonatomic,assign) NSInteger *star; 改为: @property (nonatomic,assign) NSInteger star;即可.

NotificationCenter KVC KVO Delegate总结

KVO(Key-Value- Observing): 一对多, 观察者模式,键值观察机制,它提供了观察某 一属性变化的方法,极大简化了代码. KVO底层实现: - kvo 是基于 runtime 机制实现 - 使用了 isa 混写 isa-swizzling ,当一个对象( 假设是person对象,   person的类是MYPerson)的属性值(假设 person 的 age 属性)发生改变时,系统会自动生成一个类,继承自  MYPerson : NSKVONotifying_MYPerso

转:KVC/KVO原理详解及编程指南

作者:wangzz 原文地址:http://blog.csdn.net/wzzvictory/article/details/9674431 转载请注明出处 如果觉得文章对你有所帮助,请通过留言或关注微信公众帐号wangzzstrive来支持我,谢谢! 前言: 1.本文基本不讲KVC/KVO的用法,只结合网上的资料说说对这种技术的理解. 2.由于KVO内容较少,而且是以KVC为基础实现的,本文将着重介绍KVC部分. 一.简介 KVC/KVO是观察者模式的一种实现,在Cocoa中是以被万物之源NS