KVO(key-value Observer),通过命名可以联想到,一个监视着监视着键值配对,让一个对象A来监视另一个对象B中的键值,一旦B中的受监视键所对应的值发生了变化,对象A会进入一个回调函数,有机会对于B中的受监视键值的改变立刻进行处理和应对。

注:虽然对象A中的回调函数有点像代理方法,但是回调函数的调用和键值发生变化处在同一个线程中,并非像某些代理方法会在另一个线程中进行回调。也就是说,如果对键key进行了监视,一旦键key对应的值发生了变化,就会去调用监视着的回调函数,直到回调函数跑完后键key对应值发生变化的流程才能继续。

好处就是减少胶水代码。

比如比赛比分发生了变化,如果我们不用KVO机制,我们需要告诉大屏幕控制人员,告诉网络媒体,告诉广播电台播音员,甚至告诉其他赛场的工作人员。

一个简单的KVO机制的程序

导航栏有三个元素,左边的编辑按钮,用来删除表的记录,右边的“+”按钮,用来新增表的记录,而当中的标题,用来显示最近的一次动作。开发思路大致为这样:

表视图有一个数据源dataSource,我们需要利用kVO机制去监视这个数据源,当按下“+”按钮时往数据源中添加一条数据,触发KVO,随后在KVO的回调函数中,我们将界面更新成和数据源同步。

当删除一条数据时,数据源减少一条数据,同样触发KVO并在随后KVO的回调函数中,将界面更新同步。

总体来说,无论对数据源做任何操作,我们都会在KVO的回调函数中,进行程序界面和数据源的同步工作,代码如下:

@interface ViewController : UIViewController<UITableViewDataSource,UITableViewDelegate>
{IBOutlet UITableView *_tbv;
}//遵循KVC的编码规范
@property (nonatomic,retain) NSMutableArray *dataSrc;
@property (nonatomic,retain) NSString *titleMsg;//提供KVC中对于容器键属性(dataSrc)的接口
-(NSUInteger)countOfDataSrc;
-(void)insertObject:(id)object inDataSrcAtIndex:(NSUInteger)index;
-(id)objectInDataSrcAtIndex:(NSUInteger)index;
-(void)removeObjectFromDataSrcAtIndex:(NSUInteger)index;
@end

上述代码中一共声明了两个属性变量:dataSrc作为数据源,titleMsg作为标题

由于数据源dataSrc是属于容器类型的数据,根据KVC协议需要申明并实现数组形式的几个方法

协议的时间内容中直接使用可变数组提供的功能,对上述四个接口进行实现,代码如下:

//集合属性的个数
-(NSUInteger)countOfDataSrc
{return [self.dataSrc count];
}//集合属性的新增动作
-(void)insertObject:(id)object inDataSrcAtIndex:(NSUInteger)index
{[self.dataSrc insertObject:object atIndex:index];
}//集合属性的取值动作
-(id)objectInDataSrcAtIndex:(NSUInteger)index
{return [self.dataSrc objectAtIndex:index];
}//集合属性的删除动作
-(void)removeObjectFromDataSrcAtIndex:(NSUInteger)index
{[self.dataSrc removeObjectAtIndex:index];
}

至此KVC的准备工作都做完了,继续实现KVO机制,对于界面的初始化进口位置,作如下初始化的设置

- (void)viewDidLoad
{[super viewDidLoad];// Do any additional setup after loading the view, typically from a nib.//初始化表视图(UITableView)的数据self.dataSrc = [[NSMutableArray alloc]initWithCapacity:0];self.titleMsg = @"没有动作";_tbv=[[UITableView alloc]init];////对表视图的数据进行监视////谁来监视,KVO的监视回调函数就调用谁[self addObserver:self//监视的键的路径,我们这里的属性由于只有一层,所以直接写dataSrcforKeyPath:@"dataSrc"//需要知道表数据改动时的新旧数据,方便我们研究,如果不需要,可以置为0options:NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld//KVO 触发时,我们收到的额外信息,如果不需要可以置为nilcontext:@"testContent"];[self addObserver:self forKeyPath:@"titleMsg" options:NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld context:@"testContent"];//右边的按钮,我们放增加UIBarButtonItem *addButton=[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:self action:@selector(add)];self.navigationItem.rightBarButtonItem=addButton;//左边的按钮,我们放编辑,主要提供删除功能//初始化没有数据,所以我们disable掉“编辑”按钮self.navigationItem.leftBarButtonItem=self.editButtonItem;self.navigationItem.leftBarButtonItem.enabled=NO;self.editButtonItem.title=@"编辑";//标题self.navigationItem.title=self.titleMsg;_tbv.delegate=self;[self.view addSubview:_tbv];
}

然后写上必须释放的方法

-(void)dealloc
{[self removeObserver:self forKeyPath:@"dataSrc"];[self removeObserver:self forKeyPath:@"titleMsg"];
}

随后当用户点击“+”按钮时,新增的处理函数如下:

//导航栏上增加按钮的调用方法
-(void)add
{//我们打算设置一个静态的整形记录当前的排序值static int myIndex=0;//每次进来,我们就把当前的排序值作为新增的对象//所以调用KVO提供的新增接口,插入新元素的位置始终位于最后[self insertObject:[NSString stringWithFormat:@"%d",myIndex] inDataSrcAtIndex:[self countOfDataSrc]];myIndex++;self.titleMsg=[NSString stringWithFormat:@"新增:%d",myIndex];
}

当用户点击“编辑”按钮时,被调用的系统默认的方法进行重写

//当用户单击“编辑”按钮时,对被调用的系统默认方法进行重写
-(void)setEditing:(BOOL)editing animated:(BOOL)animated
{//UIViewController 提供的editButtonItem 默认会调用此方法//所以我们重写此方法,第一步就是让表视图变成编辑状态,供我们删除内容用
    [_tbv setEditing:editing animated:animated];//第二步让super继续操作//目的是不改变UIViewController对于editButtonItem原有的动作//如果不加,那就是等于我们将这个方法截获了//效果不同体现在:editButtonItem不会在Edit状态和Done状态之间切换
    [super setEditing:editing animated:animated];if(editing){self.editButtonItem.title=@"完成";}else{self.editButtonItem.title=@"编辑";}
}

当用户按下“Delete”后,作为表视图的代理,“tableView:commitEditingStyle:forRowAtIndexPath:”,这个代理方法将会被调用,所以需要实现如下代码:

-(void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{if(editingStyle==UITableViewCellEditingStyleDelete){self.titleMsg=[NSString stringWithFormat:@"删除:[%d]",indexPath.row];[self removeObjectFromDataSrcAtIndex:indexPath.row];}
}

KVO所触发的回调函数的实现方式

//KVO监视某个属性时,当属性发生变化会受到此回调
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{if([keyPath isEqualToString:@"titleMsg"]){[self handleTitleChangeofObject:objectchange:changecontext:context];return;}NSInteger changeRow=0;//NSKeyValueChangeIndexesKey键中记录了集合属性改变位置等重要信息NSIndexSet *indices=[change objectForKey:NSKeyValueChangeIndexesKey];if(indices){//我们每次只改集合中的一处地方,所以我们可以用firstIndex来简单的取出改变的地方//如果时多处地方遭到修改,需要使用NSindexSet类提供的getIndexes方法changeRow=indices.firstIndex;}//制作NSIndexPath,为了提供给表视图进行UI更新NSIndexPath *changeIndexPath=[NSIndexPath indexPathForRow:changeRow inSection:0];//NSKeyValueChangeKindKey信息中记录了监视属性的值变化类型NSNumber *kind=[change objectForKey:NSKeyValueChangeKindKey];switch ([kind intValue]) {case NSKeyValueChangeInsertion://此新增方法后,表视图重绘
            [_tbv insertRowsAtIndexPaths:[NSArray arrayWithObjects:changeIndexPath] withRowAnimation:UITableViewRowAnimationFade];break;case NSKeyValueChangeRemoval://次删除方法后,表视图会重绘
            [_tbv deleteRowsAtIndexPaths:[NSArray arrayWithObjects:changeIndexPath] withRowAnimation:UITableViewRowAnimationFade];break;default:break;}//控制编辑按钮//如果表数据有记录if([self countOfDataSrc]>0){//让编辑按钮可用self.navigationItem.leftBarButtonItem.enabled=YES;}else{//让编辑按钮不可用,并且遵循UIVievController对于不可用时的UI处理(比如变成edit)
        [self setEditing:NO animated:YES];self.navigationItem.leftBarButtonItem.enabled=NO;}}

下列代码则是对于界面标题的更新代码

-(void)handleTitleChangeofObject:(id)objectchange:(NSDictionary *)changecontext:(void *)context
{self.navigationItem.title=self.titleMsg;
}

剩下的表视图的实现方法就不贴了

转载于:https://www.cnblogs.com/haibosoft/p/3654641.html

KVO 的使用和举例相关推荐

  1. iOS开发常用的资源和资料

    常用的三方资源地址: ASIHTTPRequest (基于http的应用所封装的同步请求,异步请求,队列请求,文件下载,cookie,cache等): http://allseeing-i.com/A ...

  2. zzz KVC/KVO原理详解及编程指南

    前言: 1.本文基本不讲KVC/KVO的用法,只结合网上的资料说说对这种技术的理解. 2.由于KVO内容较少,而且是以KVC为基础实现的,本文将着重介绍KVC部分. 一.简介 KVC/KVO是观察者模 ...

  3. KVC/KVO原理详解及编程指南

    作者:wangzz 原文地址:http://blog.csdn.net/wzzvictory/article/details/9674431 转载请注明出处 如果觉得文章对你有所帮助,请通过留言或关注 ...

  4. KVC/KVO 本质

    KVO 的实现原理 KVO是关于runtime机制实现的 当某个类的对象属性第一次被观察时,系统就会在运行期动态地创建该类的一个派生类,在这个派生类中重写基类中任何被观察属性的setter方法.派生类 ...

  5. ios-kvc\kvo 原理

    ios-kvc\kvo 原理 原文地址:http://blog.csdn.net/wzzvictory/article/details/9674431 KVC(Key-value coding)键值编 ...

  6. NSNotificationCenter消息通信机制介绍(KVO)

    作用:NSNotificationCenter是专门供程序中不同类间的消息通信而设置的. 注册通知:即要在什么地方接受消息 [[NSNotificationCenter defaultCenter]  ...

  7. 一个KVO 实现WKWebView加载进度条的例子 (注意最后移除观察者)

    // // OpenWebViewController.m // Treasure // // Created by 蓝蓝色信子 on 16/7/29. // Copyright © 2016年 GY ...

  8. Notification和KVO有什么不同

    Notification是推送通知,我们可以建立一个通知中心,存放创建多个通知,在不同的地方在需要的时候push调用 和KVO不同的是,KVO是键值观察,只能观察一个值,这就是区别 转载于:https ...

  9. linux代码动态分析软件,举例分析Linux动态库和静态库

    函数库分为静态库和动态库两种.创建Linux静态库和Linux动态库和使用它们在这里将以举例的形式详述一下.静态库在程序编译时会被连接到目标代码中,程序运行时将不再需要该静态库.动态库在程序编译时并不 ...

  10. TCP/IP基础概念及通信过程举例

    TCP/IP基础概念及通信过程举例 出现 上个世纪60年代,由于中央集中式网络的容灾性较弱,以美国国防部为中心的一家组织研究出分组交换网络.后来为了验证分组交换技术的实用性,ARPANET出现了,并且 ...

最新文章

  1. 一文讲清楚什么是迁移学习?以及它都用在哪些深度学习场景?
  2. Oracle 删除重复数据只留一条
  3. R如何与Tableau集成分步指南 - 适用于数据科学和商业智能专业人员
  4. 《唐山大地震》高清下载,迅雷下载,在线观看!
  5. 方舟服务器维护公告11月19日,明日方舟11月19日10点停机维护 更新内容一览
  6. iconpath 微信小程序_【报Bug】微信小程序 map 标记点iconPath图标 苹果手机 不能单个设置了。以前没有问题。现在不知道为啥不行了...
  7. javascript的一些常用正则表达式
  8. 日本电影《摇摆》:男人之间的心灵碰撞
  9. 预备作业03 20162320刘先润
  10. iOS工程师常用的命令行命令总结
  11. 酷我 android 目录,酷我听听:Android平台最强音乐播放器
  12. python库skimage 绘制直方图;绘制累计直方图;实现直方图匹配(histogram matching)
  13. 我常用的find命令
  14. 工具教程第十一讲:如何加入电报群
  15. 广义S变换的地震高分辨率处理中的应用
  16. 制图利器—MapGIS10.5制图版体验
  17. 七大开放式联网企业商业模式
  18. 手把手教你安装vivado2015.4开发环境
  19. 献给java初学者,非常适合新手练习的Java项目
  20. 用Proxifier只代理PC端部分软件

热门文章

  1. Markdown stackoverflow 增加中划线
  2. 地图画指定区域_善用GIS 妙绘“环卫”一图画卷
  3. 2021-09-10二叉树的层序遍历
  4. JavaWeb请求的重定向与转发:getRequestDispatcher()的forward方法,sendRedirect方法,以及重定向与转发的区别
  5. 【Codeforces Global Round 2】A-E题解 【Frets On Fire、Pavel and Triangles】
  6. 西门子S7系列中间人攻击:PLC探测和流量分析(二)
  7. 64位Win7下安装Oracle11gr2以及PL/sql(32位)安装
  8. 217.存在重复元素 (力扣leetcode) 博主可答疑该问题
  9. Springboot项目jar包部署Linux
  10. 20155201 2016-2017-2 《Java程序设计》第五周学习总结