博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
【原】IOS中KVO模式的解析与应用
阅读量:5824 次
发布时间:2019-06-18

本文共 4378 字,大约阅读时间需要 14 分钟。

最近老翁在项目中多处用到了KVO,深感这种模式的好处。现总结如下:

一、概述

KVO,即:Key-Value Observing,它提供一种机制,当指定的对象的属性被修改后,则对象就会接受到通知。简单的说就是每次指定的被观察的对象的属性被修改后,KVO就会自动通知相应的观察者了。

KVO其实也是“观察者”设计模式的一种应用。我的看法是,这种模式有利于两个类间的解耦合,尤其是对于 业务逻辑与视图控制 这两个功能的解耦合。

 

二、引子

先来看个引子:

有一个业务类:Walker,在这个类内部只负责关于业务逻辑的处理,比如负责从服务器传来的JSON中解析数据,或做其他业务数据上的处理。

有另一个类:ViewController,专门负责界面的交互与试图更新。其中,需要讲Walker的某些属性显示出来,并实时更新。

目前,据我所能想到的方法有以下几种:

方法1、直接的函数调用

Walker的类内部,把创建一个ViewController的对象,然后调用ViewController的修改界面的方法,把需要改动的属性值作为形参传给该函数。

这种方式最直观,因为它不需要绕任何弯子。但是,确实最糟的方法。因为Walker与ViewController这两个类从此紧紧耦合在一起了。记住这句话,处理业务逻辑的类,对外部的事情知道得越少越好。甚至于,要做到外部是否有VC(View Controller),有多少个VC都不影响我。假设这是一个项目,程序员A负责业务逻辑的处理,程序员B负责UI,则采取这种方式后,程序员A就受制于B,互相干扰。

 

方法2、利用消息通信机制(NSNotification)

在Walker内部建立消息中心NSNotificationCenter,把实例化之后的VC对象作为observer。Center建在Walker或者VC都无所谓,具体看我博客的另一篇文章【NSNotificationCenter总结】。这种方法比前面的方法好一些。但是有一个很大的缺点:如果Walker需要更改的属性很多而且很频繁,那么这种方式很不方便传值。而且,注意到了没,“把实例化后的VC对象作为observer”,始终逃不开在Walker内部对VC实例化。依旧是耦合着。

 

方法3、利用delegate

关于delegate的介绍有很多,这里就不多讲。但是在这种需求下用 delegate,有点“杀鸡用牛刀”感觉,成本较大,而且不直观。

 

方法4、利用KVO模式

所有的代码都将在ViewController中实现。对于Walker,它自己都不知道外部是否有VC,以及VC会怎用用我的属性。

 

三、Demo

 

1 // 2 //  Walker.h 3 //  KVOExample 4 // 5 //  Created by 老翁 on 13-7-29. 6 //  Copyright (c) 2013年 wzl. All rights reserved. 7 // 8  9 #import 
10 11 @interface Walker : NSObject12 {13 NSInteger _age;14 NSString *_name;15 }16 17 @property (nonatomic) NSInteger age;18 @property (nonatomic, retain) NSString *name;19 20 - (id)initWithName:(NSString *)name age:(NSInteger)age;21 22 23 @end
#import "Walker.h"@implementation Walker@synthesize age = _age;@synthesize name = _name;- (void)dealloc{    [_name release];    [super dealloc];}- (id)initWithName:(NSString *)name age:(NSInteger)age{    if (self = [super init]) {        _name = name;        _age = age;    }    return  self;}@end

 

ViewController代码:

////  ViewController.h//  KVOExample////  Created by 老翁 on 13-7-29.//  Copyright (c) 2013年 wzl. All rights reserved.//#import 
#import "Walker.h"@class Walker;@interface ViewController : UIViewController{ Walker *_walker; UILabel *_ageLabel;}@property (nonatomic, assign) Walker *walker;@end

 

1 // 2 //  ViewController.m 3 //  KVOExample 4 // 5 //  Created by 老翁 on 13-7-29. 6 //  Copyright (c) 2013年 wzl. All rights reserved. 7 // 8  9 #import "ViewController.h"10 11 @interface ViewController ()12 13 @end14 15 @implementation ViewController16 17 @synthesize walker = _walker;18 19 20 - (void)dealloc21 {22     [_walker release];23     [_ageLabel release];24     [super dealloc];25 }26 27 - (void)viewDidLoad28 {29     [super viewDidLoad];30     // Do any additional setup after loading the view, typically from a nib.31     _walker = [[Walker alloc] initWithName:@"老翁" age:25];32     /* 关键步骤 */33     [_walker addObserver:self34               forKeyPath:@"age"35                  options:NSKeyValueObservingOptionNew36                  context:nil];37     38     39     //UI initialization40     UIButton *btn = [UIButton buttonWithType:UIButtonTypeCustom];41     [btn setFrame:CGRectMake(120, 200, 100, 35)];42     [btn setBackgroundColor:[UIColor lightGrayColor]];43     [btn setTitle:@"增加5岁" forState:UIControlStateNormal];44     [btn addTarget:self45             action:@selector(buttonPressed)46   forControlEvents:UIControlEventTouchUpInside];47     [self.view addSubview:btn];48     49     _ageLabel = [[UILabel alloc] initWithFrame:CGRectMake(40, 150, 200, 35)];50     _ageLabel.text = [NSString stringWithFormat:@"%@现在的年龄是: %d", _walker.name, _walker.age];51     _ageLabel.backgroundColor = [UIColor clearColor];52     [self.view addSubview:_ageLabel];53     54     55 }56 57 - (void)buttonPressed58 {59     _walker.age += 5;60 }61 62 /* KVO function, 只要object的keyPath属性发生变化,就会调用此函数*/63 - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context64 {65     if ([keyPath isEqualToString:@"age"] && object == _walker) {66         _ageLabel.text = [NSString stringWithFormat:@"%@现在的年龄是: %d", _walker.name, _walker.age];67     }68 }69 70 71 72 - (void)didReceiveMemoryWarning73 {74     [super didReceiveMemoryWarning];75     // Dispose of any resources that can be recreated.76 }77 78 @end

 

  

点击了按钮之后,系统会调用 observeValueForKeyPath :函数,这个函数应该也是回调函数。在该函数内部做UI更新。我们以这种轻量级的方式达到了目的。

 本文转自编程小翁博客园博客,原文链接:http://www.cnblogs.com/wengzilin/p/3223770.html,如需转载请自行联系原作者

你可能感兴趣的文章
运维工程师在干什么学些什么?【致菜鸟】
查看>>
Linux中iptables详解
查看>>
java中回调函数以及关于包装类的Demo
查看>>
maven异常:missing artifact jdk.tools:jar:1.6
查看>>
终端安全求生指南(五)-——日志管理
查看>>
Nginx 使用 openssl 的自签名证书
查看>>
创业维艰、守成不易
查看>>
PHP环境安装套件:快速安装LAMP环境
查看>>
CSS3
查看>>
ul下的li浮动,如何是ul有li的高度
查看>>
C++ primer plus
查看>>
python mysqlDB
查看>>
UVALive 3942 Remember the Word Tire+DP
查看>>
从微软的DBML文件中我们能学到什么(它告诉了我们什么是微软的重中之重)~目录...
查看>>
被需求搞的一塌糊涂,怎么办?
查看>>
c_数据结构_队的实现
查看>>
jquery 选择器总结
查看>>
Qt设置背景图片
查看>>
【阿里云文档】常用文档整理
查看>>
java中的Volatile关键字
查看>>