KVC 实战浅析
KVC 就是 key value coding,废话!
今天我们研究的是如何使用它!
key value coding : 间接通过字符串类型的key取出对应的属性值
KVC的价值
- 1.可以访问私有成员变量的值
- 2.可以间接修改私有成员变量的值(替换系统自带的导航栏、tabbar)
举个例子:我现在要替换系统自带的tabbar,但是,系统的是“ readonly”的。解决方法是:KVC。// 替换系统的tabbar
[self setValue:[[MyTabBar alloc] init] forKeyPath:@"tabBar"]; - 我们点击@"tabBar" 进去之后会发现:是readonly 属性的。
@property(nonatomic,readonly) UITabBar *tabBar NS_AVAILABLE_IOS(3_0);
// Provided for -[UIActionSheet showFromTabBar:]. Attempting to modify the contents of the tab bar directly will throw an exception.
进一步了解
keyPath包含了key的功能
key:只能访问当前对象的属性
keyPath:能利用.运算符一层一层往内部访问属性
- 到底有啥好用???
KVC 可是Cocoa的一大招!为啥我这么说呢?
下面请看一个例子:
@interface DataModel : NSObject
@property (nonatomic,strong)NSString *applicationId;
@property (nonatomic,strong)NSString *slug;
@property (nonatomic,strong)NSString *name;
@property (nonatomic,strong)NSString *releaseDate;
@property (nonatomic,strong)NSString *version;
@property (nonatomic,strong)NSString *descriptionStr;//现在和json,key不一致
@property (nonatomic,assign)int categoryId;
@property (nonatomic,strong)NSString *categoryName;
@property (nonatomic,strong)NSString *iconUrl;
@property (nonatomic,strong)NSString *itunesUrl;
@property (nonatomic,strong)NSString *starCurrent;
@property (nonatomic,strong)NSString *starOverall;
@property (nonatomic,strong)NSString *ratingOverall;
@property (nonatomic,strong)NSString *downloads;
@property (nonatomic,strong)NSString *currentPrice;
@property (nonatomic,strong)NSString *lastPrice;
@property (nonatomic,strong)NSString *priceTrend;
@property (nonatomic,strong)NSString *expireDatetime;
@property (nonatomic,strong)NSString *releaseNotes;
@property (nonatomic,strong)NSString *updateDate;
@property (nonatomic,strong)NSString *fileSize;
@property (nonatomic,strong)NSString *ipa;
@property (nonatomic,strong)NSString *shares;
@property (nonatomic,strong)NSString *favorites; @end- 以上的model 不少了吧!我们开发时不可能像下面那样,一个一个地写吧!太Low了:
DataModel *model = [[DataModel alloc] init];
cell.xxx.text = model.name;
cell.xxx.text = model.descriptionStr;
xxx.xxx.xxx = model. applicationId;
...
...那么怎么样才能一次性解决掉这个问题呢?---用KVC
- 使用KVC 的步骤非常简单,要记住!就是重写2个方法而已!
重写2个方法:
-(void)setValue:(id)value forUndefinedKey:(NSString *)key{ } -(id)valueForUndefinedKey:(NSString *)key{
return nil;
}下面是常见使用:
- KVC的前提是保证 模型里的属性要和JSON 解析的值一致!
- 上面的模型属性里有一个和json解析不一样的字段,descriptionStr;//现在和json,key不一致 ,json解析的是description。
- 不一致的原因是模型的属性尽量不要和系统的关键字一致!所以,我们模型要避开关键字。那么问题来了,我们怎么设置值一致呢?
很简单!!!只需在重写的方法里替换就OK啦!
-(void)setValue:(id)value forUndefinedKey:(NSString *)key{ //找到和属性不一致名字的key,然后赋值给self的属性
if ([key isEqualToString:@"description"]) { // self.descriptionStr = value; // 不推荐使用
[self setValue:value forKey:@"descriptionStr"]; // 推荐
}
}- 例如:id、description等等系统关键字就可以用这种方法做了。
上面是解决关键字,也就是属性名字和系统关键字有冲突!!!,下面介绍的,也是开发中经常遇到的问题:就是对于处理“类型”,就用下面的方法:
- 类型?
- 这就是类型:服务器返回有“引号”和没引号,分别代表 NSString 和NSNumber
看有没有引号.png
- 这个对KVC 也有影响,下面我带大家 处理类型!!!
- 事实上,在企业服务器开发人员把 NSString修改成 NSNumber 类型或其它类型,他们通常是不会主动告诉你的!这是你之前可以成功运行的APP突然崩溃!这你又得花费很多时间去查找!为了避免此问题和如何处理,请看下面:
- 重写方法:
- (void)setValue:(id)value forKey:(NSString *)key{}
这里就以 NSNumber 为例子:
- (void)setValue:(id)value forKey:(NSString *)key
{
// 服务器是 NSNumber ,模型表里是 NSString类型,所以,要处理
if ([value isKindOfClass:[NSNumber class]]) { // NSNumber--> NSString
[self setValue:[NSString stringWithFormat:@"%@",value] forKey:key]; }else{
[super setValue:value forKey:key];
}
}
总结:使用KVC时,最好重写2个方法 和 一个处理 类型的方法;
下面再次回顾上面的方法使用:
#pragma mark ---- 一定要实现下面的两个方法!(属性名字用这个方法)
/**
利用kvc解析json,一定要实现下面的两个方法!(属性名字用这个方法)
*/
-(void)setValue:(id)value forUndefinedKey:(NSString *)key{
//找到和属性不一致名字的key,然后赋值给self的属性
if ([key isEqualToString:@"description"]) { // self.descriptionStr = value; // 不推荐使用
[self setValue:value forKey:@"descriptionStr"]; // 推荐
}
}
-(id)valueForUndefinedKey:(NSString *)key{
return nil;
}
#pragma mark --- 对于处理“类型”,就用下面的方法
// 处理特殊 ----(类型)例如:NSNumber--> NSString
- (void)setValue:(id)value forKey:(NSString *)key
{
// price 服务器是 NSNumber
// 服务器是 NSNumber ,模型表里是 NSString类型,所以,要处理
if ([value isKindOfClass:[NSNumber class]]) {
// NSNumber--> NSString
[self setValue:[NSString stringWithFormat:@"%@",value] forKey:key];
}else{
[super setValue:value forKey:key];
}
}
- 其实KVC的使用场景还有,这里就不介绍了!这个是在开发中非常常用的!!!
- 你感受到了KVC好处了吗?
IOS中KVC与KVO的应用解析 一、NSKeyValueCoding(KVC) 1、从一个小例子引入 KVC键值编码是Object-C为我们提供的一种对成员变量赋值的方法。在探讨其方法之前,我们先来看一个小例子: 首先,创建一个数据模型model类: ? 1 2 3 4 5 6 7 8...
IOS中KVC与KVO的应用解析
一、NSKeyValueCoding(KVC)
1、从一个小例子引入
KVC键值编码是Object-C为我们提供的一种对成员变量赋值的方法。在探讨其方法之前,我们先来看一个小例子:
首先,创建一个数据模型model类:
1
2
3
4
5
6
7
8
|
//.h文件 #import <Foundation/Foundation.h> @interface Model : NSObject { @ public //将成员变量设置为公有的 以便其他文件有访问权限 NSString * str; } @end |
我们在其他文件中有两种方法str进行赋值和取值:
1
2
3
4
5
|
Model * model = [[Model alloc]init]; model->str=@ "312" ; //普通方法赋值 [model setValue:@ "321" forKey:@ "str" ]; //kvc赋值 NSLog(@ "%@" ,model->str); //普通方法取值 NSLog(@ "%@" ,[model valueForKey:@ "str" ]); //kvc取值 |
同样的,对于用@property声明的变量,使用kvc的效果和使用点语法,setter,getter方法的效果是一样的。
2、KVC有关函数方法详解
通过上面的例子,我们已经可以简单了解KVC是干什么的了,下面是一些常用方法。
+ (BOOL)accessInstanceVariablesDirectly;
这个方法类似一个开关,默认返回为YES,表示支持KVC方式赋值,也可以在子类中将其重写,如果返回为NO,则再进行KVC会抛出异常。
- (id)valueForKey:(NSString *)key;
通过键取值
- (void)setValue:(id)value forKey:(NSString *)key;
通过字符串键给成员变量赋值
- (BOOL)validateValue:(inout id *)ioValue forKey:(NSString *)inKey error:(out NSError **)outError;
系统默认实现的方法,验证一个键值是否有效
- (NSMutableArray *)mutableArrayValueForKey:(NSString *)key;
将取到的值放入一个可变数组中
- (NSMutableOrderedSet *)mutableOrderedSetValueForKey:(NSString *)key NS_AVAILABLE(10_7, 5_0);
将取到的值放入可变的有序集合中
- (NSMutableSet *)mutableSetValueForKey:(NSString *)key;
将取到的值放入可变的集合中
- (id)valueForKeyPath:(NSString *)keyPath;
- (void)setValue:(id)value forKeyPath:(NSString *)keyPath;
上面这两个方法分别是通过路径赋值与取值,数据结构类似地图,比如在model类中有一个成员变量model2,在Model2类中有一个字符串,我们可以通过如下的方式赋值取值
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
//Model.h #import "Model2.h" @interface Model : NSObject { @ public
NSString * str;
Model2 * model2;
} //Model2.h @interface Model2 : NSObject { @ public
NSString * str2;
} @end //其他文件 Model * model = [[Model alloc]init];
Model2 * model2 = [[Model2 alloc]init];
model->model2=model2;
[model setValue:@ "123" forKeyPath:@ "model2.str2" ];
NSLog(@ "%@" ,[model valueForKeyPath:@ "model2.str2" ]);
|
- (NSMutableArray *)mutableArrayValueForKeyPath:(NSString *)keyPath;
- (NSMutableOrderedSet *)mutableOrderedSetValueForKeyPath:(NSString *)keyPath NS_AVAILABLE(10_7, 5_0);
- (NSMutableSet *)mutableSetValueForKeyPath:(NSString *)keyPath;
上面三个方法与前面类似,只是是从路径取值的。
- (id)valueForUndefinedKey:(NSString *)key;
这个方法可以获取没有提前定义的成员变量的值,比如运行时创建的,下面这个方法是给未定义的成员变量赋值
- (void)setValue:(id)value forUndefinedKey:(NSString *)key;
注意:这两个方法默认的实现会抛出异常,子类必须重写才能使用。
- (void)setNilValueForKey:(NSString *)key;
将成员变量置为nil
- (NSDictionary *)dictionaryWithValuesForKeys:(NSArray *)keys;
根据键值获取键值对字典
- (void)setValuesForKeysWithDictionary:(NSDictionary *)keyedValues;
通过字典对成员变量同意赋值,经常使用
二、NSKeyValueObservingCustomization(KVO)
KVO是一种消息监听机制,可以在某个量发生变化的时候将消息传送给监听者,因此广泛用于传值,界面低耦合等逻辑中。KVO机制的核心是以下三个方法:
- (void)addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(void *)context;
使用这个方法注册一个监听者,参数解释如下:
observer:监听者对象
keyPath:监听的参数
options:监听选项
context:参数传递
监听的选项枚举如下:
1
2
3
4
5
6
7
8
|
typedef NS_OPTIONS(NSUInteger, NSKeyValueObservingOptions) {
NSKeyValueObservingOptionNew = 0x01, //回调的字典中存放新值
NSKeyValueObservingOptionOld = 0x02, //回调的字典中存放旧值
NSKeyValueObservingOptionInitial , //值改变前进行回调
NSKeyValueObservingOptionPrior //改变前后都进行回调
}; //回调字典后面会解释 |
- (void)removeObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath context:(void *)context ;
- (void)removeObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath;
这两个方法都是用来移除监听者
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context;
这个方法是监听对象数据改变时回调的方法,change是一个字典,字典中根据监听的选项不同,存放不同的值(新或者旧)。context是传递的参数。
代码示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
- ( void )viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
model = [[Model alloc]init];
//添加监听者
[model addObserver:self forKeyPath:@ "str" options:NSKeyValueObservingOptionNew context:@ "321" ];
[model setValue:@ "qw" forKey:@ "str" ];
} - ( void )didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
} -( void )observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:( void *)context{
if ([keyPath isEqualToString:@ "str" ]) {
NSLog(@ "%@" ,context);
}
}
|
KVC 实战浅析的更多相关文章
- Go语言冒泡、选择、插入、快速排序实战浅析
Hello,各位小伙伴大家好,我是小栈君,今天为大家带来的分享是关于go语言中的排序实战浅析. 我们就实际操作关于go的冒泡排序.选择排序.插入排序和快速排序四种方式的理论和实战进行分享,希望能够为大 ...
- KVC浅析和实例
KVC 与 KVO 是 Objective C 的关键概念,个人认为必须理解的东西,下面是实例讲解. Key-Value Coding (KVC) KVC,即是指 NSKeyValueCoding,一 ...
- iOS开发——项目实战总结&Block使用注意点浅析
Block使用注意点浅析 1.在使用block前需要对block指针做判空处理. 不判空直接使用,一旦指针为空直接产生崩溃. if (!self.isOnlyNet) { if (succBlock ...
- Java并发编程原理与实战三十一:Future&FutureTask 浅析
一.Futrue模式有什么用?------>正所谓技术来源与生活,这里举个栗子.在家里,我们都有煮菜的经验.(如果没有的话,你们还怎样来泡女朋友呢?你懂得).现在女票要你煮四菜一汤,这汤是鸡汤, ...
- 从实战角度浅析snmp
Snmp Simple Network Management Protocol Snmp最终是为五花八门的网管软件服务的,由于接触的网管软件较少,所以对snmp的理解至今还仅限于初级配置阶段.以下言 ...
- MySQL实战 | 03 - 谁动了我的数据:浅析MySQL的事务隔离级别
原文链接:这一次,带你搞清楚MySQL的事务隔离级别! 使用过关系型数据库的,应该都事务的概念有所了解,知道事务有 ACID 四个基本属性:原子性(Atomicity).一致性(Consistency ...
- AndFix热修复 —— 实战与源码解析
当你的应用发布后第二天却发现一个重要的bug要修复,头疼的同时你可能想着赶紧修复重新打个包发布出去,让用户收到自动更新重新下载.但是万事皆有可能,万一隔一天又发现一个急需修复的bug呢?难道再次发布打 ...
- IOCP 浅析
http://www.ibm.com/developerworks/cn/java/j-lo-iocp/ https://msdn.microsoft.com/en-us/library/window ...
- 非等高cell实战(01)-- 实现微博页面
非等高cell实战(01)-- 实现微博页面 学习过UITableView.AutoLayout以及MVC的相关知识,接下来通过一个微博页面实战来整合一下. 首先看一下效果图: 需求分析 此页面为非等 ...
随机推荐
- SQL 课程 连接查询
今天,我主要是对前面所学习过的子查询进行了复习,然后学习了连接查询join on 的内容. 如: select renyuan.code,name,age ,sex , bumen.bname,bce ...
- WPF类层次结构
WPF类层次结构 System.Threading.DispatcherObject类 WPF应用程序使用STA(Single Thread Affinity)模型,整个用户界面由一个单独的线程拥有, ...
- ios NSComparator 三种枚举类型
NSComparator有3种枚举类型 NSOrderedDescending 降序,但是用他可以实现升序或者降序都没问题. NSOrderedAscending 升序,但是目前没有使用出任何效果.. ...
- C/C++语言的标准库函数malloc/free与运算符new/delete的区别
概括地说 1.malloc与free是C++/C的标准库函数,new/delete是C++的运算符,它们都可用于申请动态内存和释放内存. 2.对于非内部数据类型的对象而言,只用malloc/free无 ...
- 软件测试之α测试和Beta测试
实施验收测试的常用策略有三种,它们分别是: · 正式验收 · 非正式验收或Alpha 测试 · Beta 测试 因此,Alpha测试和Beta测试都属于验收测试.所谓验收测试是软件产品完成了功能测试和 ...
- Python编码介绍——encode和decode
在 python 源代码文件中,如果你有用到非ASCII字符,则需要在文件头部进行字符编码的声明,声明如下: # code: UTF-8 因为python 只检查 #.coding 和编码字符串,所以 ...
- nefu 72 N!
Description Given an integer N(0 ≤ N ≤ 10000), your task is to calculate N! Input One N in one line, ...
- Lotto
Lotto Time Limit : 2000/1000ms (Java/Other) Memory Limit : 65536/32768K (Java/Other) Total Submiss ...
- linux 进程监控和自动重启的简单实现
目的:linux 下服务器程序会因为各种原因dump掉,就会影响用户使用,这里提供一个简单的进程监控和重启功能. 实现原理:由定时任务crontab调用脚本,脚本用ps检查进程是否存在,如果不存在则重 ...
- Codeforces Round #372 (Div. 2) C 数学
http://codeforces.com/contest/716/problem/C 题目大意:感觉这道题还是好懂得吧. 思路:不断的通过列式子的出来了.首先我们定义level=i, uplevel ...