IOS中KVO模式的解析与应用

最近老翁在项目中多处用到了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 <Foundation/Foundation.h>
10
11 @interface Walker : NSObject
12 {
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 <UIKit/UIKit.h>
#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 @end
14
15 @implementation ViewController
16
17 @synthesize walker = _walker;
18
19
20 - (void)dealloc
21 {
22 [_walker release];
23 [_ageLabel release];
24 [super dealloc];
25 }
26
27 - (void)viewDidLoad
28 {
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:self
34 forKeyPath:@"age"
35 options:NSKeyValueObservingOptionNew
36 context:nil];
37
38
39 //UI initialization
40 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:self
45 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)buttonPressed
58 {
59 _walker.age += 5;
60 }
61
62 /* KVO function, 只要object的keyPath属性发生变化,就会调用此函数*/
63 - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
64 {
65 if ([keyPath isEqualToString:@"age"] && object == _walker) {
66 _ageLabel.text = [NSString stringWithFormat:@"%@现在的年龄是: %d", _walker.name, _walker.age];
67 }
68 }
69
70
71
72 - (void)didReceiveMemoryWarning
73 {
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

欢迎私下交流学习:

QQ 719113951

##################################################

 
 
标签: KVO

IOS中KVO模式的解析与应用的更多相关文章

  1. 【原】IOS中KVO模式的解析与应用

    最近老翁在项目中多处用到了KVO,深感这种模式的好处.现总结如下: 一.概述 KVO,即:Key-Value Observing,它提供一种机制,当指定的对象的属性被修改后,则对象就会接受到通知.简单 ...

  2. js中State模式的解析及运用

     状态模式,在大的范畴中的定义为当一个对象的内在状态改变时允许改变其行为,这个对象看起来像是改变了其类.每种编程语言有不同的实现方式,运用的范围也多用于游戏之中. 这里我用javascript来模拟状 ...

  3. iOS 中架构模式的浅显理解

    我们开发软件中应用各种模式,主要是为了 职责划分:一个类只做一件事 易用,可维护,方便扩展 解耦,相互独立,可单独测试 各种设计模式其实都是在解决上面的问题,让我们对比看看吧. 一.如何理解MVC设计 ...

  4. iOS中UITextField 使用全面解析

    //初始化textfield并设置位置及大小   UITextField *text = [[UITextField alloc]initWithFrame:CGRectMake(20, 20, 13 ...

  5. iOS中UITextField 使用全面解析 分类: ios技术 2015-04-10 14:37 153人阅读 评论(0) 收藏

    //初始化textfield并设置位置及大小   UITextField *text = [[UITextField alloc]initWithFrame:CGRectMake(20, 20, 13 ...

  6. iOS中 KVO 键值观察者

    KVO Key-Value-Obsever 键值观察者 1.首先要有一个观察者,此时被观察者是自己找一个观察者观察自己的key值对应的value值有没有改变,如果改变了就可以做一些响应的操作 创建一个 ...

  7. iOS边练边学--iOS中的XML数据解析

    XML的解析方式 SAX 大小文件都可以 NSXMLParser DOM 最好是小文件 GDataXML NSXMLParser的用法 创建解析器来解析 // 创建XML解析器 NSXMLParser ...

  8. iOS边练边学--iOS中的json数据解析

    JSON数据(NSData) -> OC对照表 {} -> NSDictionary @{} [] -> NSArray @[] "jack" -> NSS ...

  9. ios中xml和html解析(封装)

    下载地址  http://pan.baidu.com/share/link?shareid=2902188921&uk=923776187 GDataXML和TFHpple配置是一样的(配置方 ...

随机推荐

  1. Redis源代码分析(二十七)--- rio制I/O包裹

    I/O每个操作系统,它的一个组成部分.和I/O业务质量,在一定程度上也影响了系统的效率. 今天,我在了解了Redis中间I/O的,相同的,Redis在他自己的系统中.也封装了一个I/O层.简称RIO. ...

  2. 用python 爬取网页图片

    import re import string import sys import os import urllib url="http://tieba.baidu.com/p/252129 ...

  3. asp.net webform easyui

    建议使用   html 页面 和 一般处理程序,一般处理程序 继承 IRequiresSessionState  ,才能用 session .

  4. Javscript轮播 支持平滑和渐隐两种效果(可以只有两张图)

    原文:Javscript轮播 支持平滑和渐隐两种效果(可以只有两张图) 先上两种轮播效果:渐隐和移动   效果一:渐隐 1 2 3 4 效果二:移动 1 2 3 4 接下来,我们来大致说下整个轮播的思 ...

  5. 浅谈javascript性能-管理内存

    上次说到,javascript脚本到底应该放在哪里?用什么用处? 以下2点: 在Html.Body部分中的JS会在页面加载的时候执行.即-用户触发一个事件的时候执行的脚本.eg:onload事件... ...

  6. 关于Java中List对象的分页思想,按10个或者n个数对list进行分组

    try { List<String> timelist = DateUtils.getDateListBySETime("2015-08-01", "2015 ...

  7. ubuntu下使用openocd+jlink进行STM32开发调试

    安装openocd就不用多说了,使用 apt-get install openocd 这个命令就可以做到. 对于使用stm32w系列的MCU,需要下载新的openocd-0.7及以上版本才能支持.0. ...

  8. mysql编码的那点事

    Mysql编码问题  在php页面可以向mysql插入英文字符,但就是不能插入中文字符,在cmd客户端也可从插入,这是困扰我两天的问题. 在网上找了很多资料,最终确定了是字符编码这个地方出现了问题,首 ...

  9. 使用WCF订阅替换轮训

    之前因为某些特定岗位的人不知道是不方便还是什么的原因,所以随便做了个独立于所有系统之外的邮件审批服务,功能是那些人在邮件里给待审批单据发个“同意”就自动审批通过,大致分为3部分:第一部分每隔固定时间去 ...

  10. 【转】视差滚动(Parallax Scrolling)效果的原理和实现

    原文:http://www.cnblogs.com/JoannaQ/archive/2013/02/08/2909111.html 视差滚动(Parallax Scrolling)是指让多层背景以不同 ...