一. 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的更多相关文章

  1. 11. KVC And KVO

    1. KVC And KVO  的认识 KVC/KVO是观察者模式的一种实现  KVC全称是Key-value coding,翻译成键值编码.顾名思义,在某种程度上跟map的关系匪浅.它提供了一种使用 ...

  2. iOS - 详细理解KVC与KVO

    详细理解KVC与KVO 在面试的时候,KVC与KVO有些时候还是会问到的,并且他们都是Objective C的关键概念,在这里我们先做一个简单地介绍: (一)KVC: KVC即指:NSKeyValue ...

  3. KVC 与 KVO 理解

    KVC 与 KVO 是 Objective C 的关键概念,个人认为必须理解的东西,下面是实例讲解. Key-Value Coding (KVC) KVC,即是指 NSKeyValueCoding,一 ...

  4. 【原】iOS中KVC和KVO的区别

    在iOS开发中经常会看到KVC和KVO这两个概念,比较可能混淆,特地区分一下 KVC(Key Value Coding) 1> 概述 KVC:Key Value Coding,键值编码,是一种间 ...

  5. IOS之KVC和KVO(未完待续)

    *:first-child { margin-top: 0 !important; } body > *:last-child { margin-bottom: 0 !important; } ...

  6. KVC和KVO的区别

    kvc和kvo 1.kvc Key-Value Coding (KVC) KVC,即是指 NSKeyValueCoding,一个非正式的 Protocol,提供一种机制来间接访问对象的属性.KVO 就 ...

  7. 谈KVC、KVO(重点观察者模式)机制编程

    一不小心,小明在<跟着贝尔去冒险>这个真人秀节目中看到了“一日警察,一世警察”的Laughing哥,整个节目除了贝尔吃牛睾丸都不用刀叉的不雅餐饮文化外,还是镜头少普通话跟小明一样烂的Lau ...

  8. iOS中关于KVC与KVO知识点

    iOS中关于KVC与KVO知识点 iOS中关于KVC与KVO知识点  一.简介 KVC/KVO是观察者模式的一种实现,在Cocoa中是以被万物之源NSObject类实现的NSKeyValueCodin ...

  9. 聊聊 KVC 和 KVO 的高阶应用

    KVC, KVO 作为一种魔法贯穿日常Cocoa开发,笔者原先是准备写一篇对其的全面总结,可网络上对其的表面介绍已经够多了,除去基本层面的使用,笔者跟大家谈下平常在网络上没有提及的KVC, KVO进阶 ...

  10. KVC 与 KVO 理解-b

    KVC 与 KVO 是 Objective C 的关键概念,个人认为必须理解的东西,下面是实例讲解. Key-Value Coding (KVC) KVC,即是指 NSKeyValueCoding,一 ...

随机推荐

  1. hdu1695 GCD(莫比乌斯反演)

    题意:求(1,b)区间和(1,d)区间里面gcd(x, y) = k的数的对数(1<=x<=b , 1<= y <= d). 知识点: 莫比乌斯反演/*12*/ 线性筛求莫比乌 ...

  2. C#/ASP.NET定时任务执行管理器组件–FluentScheduler定时器

    必须JobManager初始化 方式1: public void Start()         {             JobManager.AddJob(() => FetchingDa ...

  3. javascript中的自执行函数

    学习es6的时候遇到了自执行函数,感觉有必要写下来,一方面加深自己的记忆,另一方面还能分享给大家. 什么是自执行函数? 自执行函数就是为了不污染全局变量命名空间的一中匿名函数,相当于自己创建了一个作用 ...

  4. github如何删除一个(repository)仓库

    GitHub 是一个面向开源及私有软件项目的托管平台,因为只支持 Git 作为唯一的版本库格式进行托管,故名 GitHub.作为开源代码库以及版本控制系统,Github拥有140多万开发者用户.随着越 ...

  5. docker学习(1) 安装

    docker是啥就不多讲了,简言之就是更轻量.更牛叉的新一代虚拟机技术.下面是安装步骤: 一.mac/windows平台的安装 docker是在linux内核基础上发展而来的,无法直接运行在mac/w ...

  6. 如何用TypeScript开发微信小程序

    微信小程序来了!这个号称干掉传统app的玩意儿虽然目前处于内测阶段,不过目前在应用号的官方文档里已经放出了没有内测号也能使用的模拟器了. 工具和文档可以参考官方文档:https://mp.weixin ...

  7. 单独使用Mybatis的配置文件

    <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE configuration PUBLIC & ...

  8. error: failed to push some refs to 'https://github.com/github账号/learn_git.git' hint: Updates were rejected because the remote contains work that you do hint: not have locally. This is usually caus

    在使用git 对源代码进行push到gitHub时可能会出错,信息如下   此时很多人会尝试下面的命令把当前分支代码上传到master分支上. $ git push -u origin master ...

  9. JDBC判断数据库是否插入成功

    package com.xujianyou; import java.sql.*; public class TestConnect { public static void main(String ...

  10. maven: 基本使用

    1.项目管理工具:Maven的repository,说白了就是dependency的仓库,它按照一定的规则将dependency存放起来,以作缓存,如果本机的 repository找不到某个depen ...