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
##################################################
相关文章:

C 到C++的升级
C所有的变量都可以在需要使用时再定义。 C语言中的变量都必须在作用域开始的位置定义。 register 关键字请求编译器将局部变量存储于寄存器中 在C语言无法获取register 变量的地址 在C中可以取得 register 变量的地址 C编译器有自己的优化方式,所以几乎不用registe…

SET QUOTED_IDENTIFIER OFF语句的作用
先看下面几个sql语句 1SETQUOTED_IDENTIFIER ON2SELECT*FROM"USER" WHEREanetasp34SETQUOTED_IDENTIFIER ON5SELECT*FROM[USER]WHEREanetasp67SETQUOTED_IDENTIFIER OFF8SELECT*FROM[USER]WHEREa"netasp" 910SETQUOTED_IDENTIFIER OFF11SELECT*FROM[USE…
proxy实现 mysql 读写分离
实现 mysql 读写分离 图解: 环境: iptables 和 selinux 关闭 proxy:test2 172.25.1.2 Master: test3 172.25.1.3 Slave:test4 172.25.1.4 环境已经实现 test3(master) 和 test4(slave) 的主从复制 Server2: [roottest2 ~]# ls mysql-proxy-0.8.5-linux-el6-x86-64bit.tar.gz …

iOS开发中用到的一些第三方库
下面是我在开发中用到的一些优秀的iOS第三方开源库: 1.AFNetworking(网络请求,类似的还有ASIHTTPRequest) https://github.com/AFNetworking/AFNetworking/ 2.MBProgressHUD(提示框) https://github.…

小图标外链API
网页上有些分享的小图标,比如分享到facebook,weibo,qq空间等功能的时候,图标以前一般是自己做一个css sprite。当一个网站的图标变了的时候,比如facebook变成assbook的时候,你就要修改这个css sprite。费时…

转载JQuery 获取设置值,添加元素详解
转载原地址 http://www.cnblogs.com/0201zcr/p/4782476.html jQuery 获取内容和属性 jQuery DOM 操作 jQuery 中非常重要的部分,就是操作 DOM 的能力。 jQuery 提供一系列与 DOM 相关的方法,这使访问和操作元素和属性变得很容易。 提示:DOM …
mysql 主从复制 和基于gtid的mysql主从复制
主从复制 原理: mysql 无需借助第三方工具,而是其自带的同步复制功能,另外一点,mysql 的主从 复制并不是从硬盘给上文件直接同步,而是逻辑的 binlog 日志同步到本地的应用执行的过 程。 数据从一个 mysql 数据库(master)复制到另一个 mysql 数据库(slave),在 master 与 slave …

使用read write 读写socket
一旦,我们建立好了tcp连接之后,我们就可以把得到的fd当作文件描述符来使用。 由此网络程序里最基本的函数就是read和write函数了。 写函数: ssize_t write(int fd, const void*buf,size_t nbytes); write函数将buf中的nbytes字节内容写入文件…
iOS从通讯录中选择联系人
有时候APP需要用户输入一位联系人的姓名和电话,除了用户手动输入,一般也允许用户从通讯录中选择一位联系人(图1),下面的代码就是使用系统的<AddressBookUI/AddressBookUI.h>库实现这一需求。 图1 完整代码&…

document.readystate
http://www.cnblogs.com/lhb25/archive/2009/07/30/1535420.html http://www.cnblogs.com/haogj/archive/2013/01/15/2861950.html http://jincuodao.baijia.baidu.com/article/2896 电视转载于:https://www.cnblogs.com/daishuguang/p/3523783.html

Openstack安装部署
系统版本 rhel7.4 关闭 iptables 关闭 selinux foundation1: 172.25.254.1 server1: 172.25.254.11 server2: 172.25.254.12 可参考:https://docs.openstack.org/mitaka/zh_CN/install-guide-rdo/ //选择的mitaka 虚拟机上网 首先物理机必须可…

在Xcode中使用Git进行源码版本控制
本文翻译自Understanding Git Source Control in Xcode (译者myShire)欢迎您加入我们的翻译小组。 在应用程序开发过程中,很重要的一部分工作就是如何进行源码的版本控制。当代码出现问题时,我们就需要将代码恢复到原先正常的版本…

敏捷开发之道(二)极限编程XP
上次的博文敏捷开发之道(一)敏捷开发宣言中,我们介绍了一下敏捷开发宣言,在其中,我们了解到了关于敏捷开发的几个重要的价值观。今天我们来了解一个敏捷开发的方法——极限编程XP 1、介绍 极限编程(eXtreme…

spring 3.X与jdk 1.8不兼容
1、报错(部分) 2、解决 虽然Spring的jdk要求如下,但是spring 3与jdk1.8不兼容(使用的是spring 3.2) 在eclipse将jdk版本下调。这里将JDK调到1.7(在eclipse如下设置) 同时,需要设置服…

rhel-server-7.5-x86_64-dvd.iso镜像下载及rar压缩包的解压
主机名为server1 [rootserver1 ~]# ls rhel-server-7.5-x86_64-dvd.part1.rar rarlinux-5.6.1.tar.gz rhel-server-7.5-x86_64-dvd.part2.rar 1、如果没有rarlinux-5.6.1.tar.gz包可以去 https://www.rarlab.com/download.htm 这个网站下载RAR 5.61 for Linux 或者RAR 5.…
Expandable Table的Demo
在网上看到一个可点击cell展开的TableView的demo,原文是swift语言,我写了个oc版,有兴趣的朋友可以看下: 效果: oc源码(带中文注释):http://download.csdn.net/detail/dolacmeng/941…

Java对多线程的支持
Java运行时系统实现了一个用于调度线程执行的线程调度器,用于确定某一时刻由哪一个线程在CPU上运行。在Java技术中,线程通常是抢占式的而不需要时间片分配进程(分配给每个线程相等的CPU时间的进程)。抢占式调度模型就是许多线程处…

ESP8266-iot-2
1.SDK概述 复制相关的工程文件到HelloWorld里面 要在版本esp8266_nonos_sdk_v2.0.0_16_07_19上面开发,那么就要复制相应文件 然后打开IDE 导入HelloWorld到工程里面 创建3个文件,如下图 再从lib里面添加文件 复制到我的下面 复制app里面的内容 打算从IoT…

iptables防火墙策略
环境: foundation1 172.25.1.250 172.25.254.1 server1 172.25.1.1 server2 172.25.1.2 server3 172.25.1.3 四个主机都做解析 iptables简介: netfilter/iptables(简称为iptables…

ubuntu(16.04.01)学习-day1
1.修改root用户密码 sudo passwd root 按提示进行设置。 2.从Ubuntu 16.04开始,用户可以实现改变启动器的位置,可以将启动器移到屏幕底部,但是无法移到右边或顶部。打开终端,然后输入下面这个命令,即可将启动器移到屏幕…

HDU 1090 A+B for Input-Output Practice (II)
#include <cstdio> int main() {int n,a,b;scanf("%d",&n);for (int i1; i<n; i){ scanf("%d%d",&a,&b);printf("%d\n",ab);}return 0; } 转载于:https://www.cnblogs.com/forever97/p/3539605.html

监听UIWebView点击视频播放的事件
最近项目需要统计在跳转UIWebView后,用户点击网页上的视频进行播放的概率。找了很多监听进入视频播放的方法,最后在stackoverflow找到下面这个使用Notification的可行方法(如果是弹出): #pragma mark Notification - (void)addNotification {…

linux系统下redhat7之虚拟机控制
基础操作: [kioskfoundation0 Desktop]$ rht-vmctl start desktop ###开启desktop虚拟机 Error: desktop not started (is already running) ###报错,desktop已经运行 [kioskfoundation0 Desktop]$ rht-vmctl view desktop …
如何设计一个 iOS 控件?(iOS 控件完全解析)
前言 一个控件从外在特征来说,主要是封装这几点: 交互方式显示样式数据使用 对外在特征的封装,能让我们在多种环境下达到 PM 对产品的要求,并且提到代码复用率,使维护工作保持在一个相对较小的范围内;而一个…

Chapter12:动态内存
智能指针——shared_ptr为了更容易地使用动态内存,新的标准提供了智能指针来管理动态对象。智能指针的行为类似常规指针,重要的区别是它负责自动释放指向的对象。 智能指针的使用方式与普通指针类似。解引用一个智能指针返回它指向的对象。 1 if (p1 &am…

判断JS对象是否拥有某属性两种方式
方式,但稍有区别 1,in 运算符 1 2 3 var obj {name:jack}; alert(name in obj); // --> true alert(toString in obj); // --> true 可看到无论是name,还是原形链上的toString,都能检测到返回true。 2,hasOwnP…

Linux之redhat7系统结构
一.linux系统结构 linux是一个倒树结构 linux中所有的东西都是文件 这些文件都在系统顶级目录“/” /就是根目录 /目录以下为二级目录这些目录都是系统装机时系统自动建立的 二级目录的作用 /bin ##二进制可执行文件也就是系统命令 /sbin ##系统管理命令存放位置 /boot …

ASP.NET优化
源地址:http://www.cnblogs.com/wangjingblogs/archive/2013/02/27/2934706.html http://jingyan.baidu.com/article/2d5afd69bfd0ff85a3e28e6d.html转载于:https://www.cnblogs.com/haizine/p/5841771.html
3D Touch介绍: 一个数字压力器App和Quick Actions
随着iPhone 6s and 6s Plus的发布,苹果介绍了全新的手机交互方式:重按手势。你应该知道,这个特性其实早已应用在苹果手表和MacBook产品中,名字叫Force Touch。它给用户交互添加了全新的维度! 或许你对Force Touch为什么…

一些LUA函数(转载)
转自http://hi.baidu.com/chevallet/item/9a3a6410c20d929198ce3363 一些LUA函数 1、assert (v [, message]) 功能:相当于C的断言,当表达式v为nil或false将触发错误, message:发生错误时返回的信息,默认为"assertion f…