KVC 和 KVO
一. KVC
1.KVC介绍
KVC 就是键值编码(key-value-coding)。
2.KVC 的主要作用:
(1)通过键值路径为对象的属性赋值。主要是可以为私有的属性赋值。
AppleViewController *appleVC = [[AppleViewController alloc]init];
[appleVC setValue:@"橘子" forKey:@"name"];
如果对象A的属性是一个对象B,要设置对象B的属性
[person setValue:@"旺财" forKeyPath:@"dog.name"];
(2)通过键值路径获取属性的值。主要是可以通过key获得私有属性的值。
NSString *nameStr = [appleVC valueForKey:@"name"];
也可以通过keypath获得值
NSString *dName = [person valueForKeyPath:@"dog.name"];
(3)将字典转型成Model,方法:setValuesForKeysWithDictionary:

// 定义一个字典
NSDictionary *dict = @{
@"name" : @"jack",
@"money" : @"20.7",
};
// 创建模型
Person *p = [[Person alloc] init]; // 字典转模型
[p setValuesForKeysWithDictionary:dict];
NSLog(@"person's name is the %@",p.name);

注意:字典的key和Model的属性一定要一一对应。否则会出现错误。比如person里没有name的属性,系统报错如下:
'[<Person 0x60000001d0b0> setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key name.'
(4)常用方法
它提供了一种使用字符串而不是访问器方法去访问一个对象实例变量的机制。
1.通过key(成员变量的名称)设置value(成员变量的值)
- (void)setValue:(id)value forKey:(NSString *)key;
2.通过keyPath(成员变量的路径)设置value(成员变量的值)
- (void)setValue:(id)value forKeyPath:(NSString *)keyPath;
3.通过key(成员变量的名称)获取value(成员变量的值)
- (id)valueForKey:(NSString *)key;
4.通过keyPath(成员变量的路径)获取value(成员变量的值)
- (id)valueForKeyPath:(NSString *)keyPath;
5.重写此方法防止出现未定义key值的时候出现崩溃
- (void)setValue:(id)value forUndefinedKey:(NSString *)key;
6.重写此方法防止获取未定义key值的时候出现崩溃
- (id)valueForUndefinedKey:(NSString *)key;
7.通过键值对的形式给成员变量赋值
- (void)setValuesForKeysWithDictionary:(NSDictionary *)keyedValues;
举个简单的例子:一个对象拥有某些属性。比如说,一个 Person 对象有一个 perName,uid,perID和一个 sex 属性。以 KVC 说法,Person 对象分别有一个 value 对应他的 perName,uid,perID和一个 sex 的 key。 key 只是一个字符串,它对应的值可以是任意类型的对象。从最基础的层次上看,KVC 有两个方法:一个是设置 key 的值,另一个是获取 key 的值。
#import <Foundation/Foundation.h> @interface Person : NSObject @property (nonatomic,copy)NSString *perName;
@property (nonatomic,copy)NSString *sex;
@property (nonatomic,copy)NSString *uid;
@property (nonatomic,copy)NSString *perID; @end
#import "Person.h"
@implementation Person
-(void)setValue:(id)value forKey:(NSString *)key{
//判断是否为NSNumber类型
if ([value isKindOfClass:[NSNumber class]]) {
[self setValue:[NSString stringWithFormat:@"%@",value] forKey:key];
}else {
//调用父类的方法
[super setValue:value forKey:key];
}
}
-(void)setValue:(id)value forUndefinedKey:(NSString *)key{
//手动赋值
if ([key isEqualToString:@"id"]) {
[self setValue:value forKey:@"perID"];
}else{
NSLog(@"未定的key值:%@",key);
}
}
-(id)valueForUndefinedKey:(NSString *)key{
NSLog(@"未找到key:%@",key);
return nil;
}
- (NSString *)description
{
return [NSString stringWithFormat:@"name = %@,sex = %@,ID= %@,perID = %@", _perName,_sex,_uid,_perID];
}
@end
#import <Foundation/Foundation.h>
#import "Person.h" int main(int argc, const char * argv[]) {
@autoreleasepool { Person *per = [Person new]; //模拟返回的服务器数据
NSDictionary *dictionary = @{@"perName":@"小红",@"sex":@"女",@"uid":[NSNumber numberWithInteger:888],@"id":@"12345"}; //通过KVC一次性给3个成变量赋值
[per setValuesForKeysWithDictionary:dictionary]; NSLog(@" %@",per); }
return 0;
}
========================================
二. KVO
1.KVO介绍:
KVO 是键值观察者(key-value-observing)。KVO提供了一种观察者的机制,通过对某个对象的某个属性添加观察者,当该属性改变,就会调用"observeValueForKeyPath:"方法,为我们提供一个“对象值改变了!”的时机进行一些操作。
2.KVO原理
当某个类的对象第一次被观察时,系统在运行时会创建该类的派生类,改派生类中重写了该对象的setter方法,并且在setter方法中实现了通知的机制。派生类重写了class方法,以“欺骗”外部调用者他就是原先那个类。系统将这个类的isa指针指向新的派生类,因此改对象也就是新的派生类的对象了。因而改对象调用setter就会调用重写的setter,从而激活键值通知机制。此外派生类还重写了delloc方法来释放资源。
3.KVO的使用
(1)给对象的属性添加观察者
[appleVC addObserver:self forKeyPath:@"name" options: NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld context:NULL];
注: options: NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld 返回未改变之前的值和改变之后的值 context可以为空
(2)若该属性发生改变,系统自动调用下面的方法:

-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context
{
//拿到新值/旧值,进行操作
NSLog(@"newValue----%@",change[@"new"]);
NSLog(@"oldValue----%@",change[@"old"]); }

(3)取消监听
-(void)dealloc
{
[person removeObserver:self forKeyPath:@"test"];
}
4.KVO的使用场景
KVO用于监听对象属性的改变。
(1)下拉刷新、下拉加载监听UIScrollView的contentoffsize;
(2)webview混排监听contentsize;
(3)监听模型属性实时更新UI;
(4)监听控制器frame改变,实现抽屉效果。
(5)方法和举例
提供了一种当其它对象属性被修改的时候能通知当前对象的机制
1.添加观察者
- (void)addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(void *)context;
2.对象被释放之前,要移除观察者,通常写在dealloc函数当中
- (void)removeObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath;
3.当属性值发生变化之后的回调函数
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context;
监听一个contentSize的例子:点击一个加号会添加10个cell

#import "ViewController.h" @interface ViewController ()<UITableViewDataSource,UITableViewDelegate> @property (nonatomic,assign)NSInteger count;//控制行数
@property (nonatomic,assign)CGSize recordSize;//记录当前UITableView的ContentSize;
@property (weak, nonatomic) IBOutlet UITableView *myTableView; @end @implementation ViewController -(void)dealloc{ //移除观察者
[self.myTableView removeObserver:self forKeyPath:@"contentSize"]; } - (void)viewDidLoad {
[super viewDidLoad]; //观察myTableView的contentSize
[self.myTableView addObserver:self forKeyPath:@"contentSize" options:NSKeyValueObservingOptionOld | NSKeyValueObservingOptionNew context:nil]; //设置导航栏右侧按钮
self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"+" style:UIBarButtonItemStylePlain target:self action:@selector(add)]; self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"__" style:UIBarButtonItemStylePlain target:self action:nil]; } //增加行数
-(void)add{ self.count += 10; //刷新UI
[self.myTableView reloadData];
//self.recordSize = self.myTableView.contentSize; //NSLog(@"%f",self.recordSize.height);
}
#pragma mark- KVO回调方法
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context{ //判断是否为对应的观者属性
if ([keyPath isEqualToString:@"contentSize"] && object == self.myTableView) { NSLog(@"%@ %f",change, self.recordSize.height); //记录变化之后的contentSize
self.recordSize = [change[@"new"] CGSizeValue]; } } #pragma mark- UITableView代理
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{ return self.count;
} -(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{ return 1;
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{ UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cell"]; if (!cell) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"cell"];
} cell.textLabel.text = @"哈哈"; return cell; } @end
如果对你有帮助,请关注我哦!
KVC 和 KVO的更多相关文章
- 11. KVC And KVO
1. KVC And KVO 的认识 KVC/KVO是观察者模式的一种实现 KVC全称是Key-value coding,翻译成键值编码.顾名思义,在某种程度上跟map的关系匪浅.它提供了一种使用 ...
- iOS - 详细理解KVC与KVO
详细理解KVC与KVO 在面试的时候,KVC与KVO有些时候还是会问到的,并且他们都是Objective C的关键概念,在这里我们先做一个简单地介绍: (一)KVC: KVC即指:NSKeyValue ...
- KVC 与 KVO 理解
KVC 与 KVO 是 Objective C 的关键概念,个人认为必须理解的东西,下面是实例讲解. Key-Value Coding (KVC) KVC,即是指 NSKeyValueCoding,一 ...
- 【原】iOS中KVC和KVO的区别
在iOS开发中经常会看到KVC和KVO这两个概念,比较可能混淆,特地区分一下 KVC(Key Value Coding) 1> 概述 KVC:Key Value Coding,键值编码,是一种间 ...
- IOS之KVC和KVO(未完待续)
*:first-child { margin-top: 0 !important; } body > *:last-child { margin-bottom: 0 !important; } ...
- KVC和KVO的区别
kvc和kvo 1.kvc Key-Value Coding (KVC) KVC,即是指 NSKeyValueCoding,一个非正式的 Protocol,提供一种机制来间接访问对象的属性.KVO 就 ...
- 谈KVC、KVO(重点观察者模式)机制编程
一不小心,小明在<跟着贝尔去冒险>这个真人秀节目中看到了“一日警察,一世警察”的Laughing哥,整个节目除了贝尔吃牛睾丸都不用刀叉的不雅餐饮文化外,还是镜头少普通话跟小明一样烂的Lau ...
- iOS中关于KVC与KVO知识点
iOS中关于KVC与KVO知识点 iOS中关于KVC与KVO知识点 一.简介 KVC/KVO是观察者模式的一种实现,在Cocoa中是以被万物之源NSObject类实现的NSKeyValueCodin ...
- 聊聊 KVC 和 KVO 的高阶应用
KVC, KVO 作为一种魔法贯穿日常Cocoa开发,笔者原先是准备写一篇对其的全面总结,可网络上对其的表面介绍已经够多了,除去基本层面的使用,笔者跟大家谈下平常在网络上没有提及的KVC, KVO进阶 ...
- KVC 与 KVO 理解-b
KVC 与 KVO 是 Objective C 的关键概念,个人认为必须理解的东西,下面是实例讲解. Key-Value Coding (KVC) KVC,即是指 NSKeyValueCoding,一 ...
随机推荐
- Windows 上如何安装Sqlite
对SQLite文明已久,却是从来没使用过,今天就来安装试用下. 一.安装 下载地址:http://www.sqlite.org/download.html 将Precompiled Binaries ...
- [LeetCode] Decode Ways 解码方法
A message containing letters from A-Z is being encoded to numbers using the following mapping: 'A' - ...
- Cocos2dx 3.12 在AndroidStudio上编译配置
转载请标明出处:http://www.cnblogs.com/studweijun/p/5805576.html SDK,NDK,ANT的配置请看这里http://www.cnblogs.com/st ...
- 使用Minicom基于串口调试HiKey
虽然通过adb shell调试方便,但是有些时候不得不借助于串口进行调试,比如测试suspend to ram之类的功能时,adb服务被关闭. 同时在minicom中也可以进入shell,进行操作. ...
- AngularJS指令
1. AngularJS指令的特点: AngularJS通过被称为指令的新属性来扩展HTML,指令的前缀为ng-. AngularJS通过内置的指令来为应用添加功能. AngularJS允许你自定义指 ...
- 【日常操作记录】Asp.Net Core 的一些基本操作或属性
用于记录在项目中使用到的方法.属性.操作,持续更新中 静态文件的使用 在项目中静态文件的使用需要在Startup中的Configure方法中增加: //使用静态文件 app.UseStaticFile ...
- java学习笔记之IO一()
1.缓冲输入文件 2.从内存输入 3.格式化的内存输入 4.基本的文本输出 示例: public class BrAndBwOrPwDemo { public static void main(Str ...
- py-faster-rcnn几个辅助脚本
py-faster-rcnn本身代码很棒. 不过使用它的时候,还是需要自己写一些脚本,作为辅助. 1 所有.py文件顶部添加utf8编码声明.因为有时候需要添加中文注释,不声明编码会报错 #inser ...
- java 方法
方法命名规范要求 类的命名规范:“全部单词的 首字母必须大写”.那么在定义方法的时候也是有命名规范要求的:“第 一个单词的首字母小写,之后每个单词的首字母大写”,那么这就是方法 的命名规范. 递归调用 ...
- MYSQL远程登录权限设置 ,可以让Navicat远程连接服务器的数据库
Mysql默认关闭远程登录权限,如下操作允许用户在任意地点登录: 1. 进入mysql,GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY ...