IOS设计模式-观察者模式
前言:23种软件设计模式中的观察者模式,也是在软件开发中,挺常用的一种设计模式。而在苹果开发中,苹果Cocoa框架已经给我们实现了这个设 计模式,那就是通知和KVO(Key-Value Observing),本篇博文将会先讲解通知和KVO的常用方法和使用示例,然后讲解观察者模式以及对观察者模式的实现。
文章内容大纲:
1、KVO的使用
2、通知的使用
3、观察者模式
正文:
1、KVO的使用
addObserver:forKeyPath:options:context:
通知其他对象的方法,这个方法在NSObject中就已经申明了,也就是说任何继承自NSObject的对象都可以使用KVO.
我们来实现一个对象a值改变的时候去通知对象b,也就是说这里b就是a的观察者,b观察a的变化,然后做出相应的反应.
Model_A.h和Model_A.m:

Model_B.h和Model_B.m:

最后在ViewController.h中:

输出结果:
2016-03-10 18:02:39.955 KVO[24772:539854] 程序开始执行!
2016-03-10 18:02:41.959 KVO[24772:539854] Model_B
-----------------------------------------------------------------------------------------------------------------------------------------------------------
如果注释掉Model_B中的方法observeValueForKeyPath:ofObject:change:context:,运行时会导致崩溃:

也就是这么一层关系:
A对象要通知B对象,B对象必须实现监听的方法,否则一旦有消息发送就会导致崩溃.
A对象不想通知B对象了,需要从B对象身上移除掉通知.
要想程序不出现问题,我们需要实现3步.
(主动添加B的通知) A -------> B(不实现一个方法就崩溃)
(主动移除B的通知) A ---X--> B
(重复移除B的通知) A ---X--> B(崩溃)
用起来很恶性,还好,我们可以重复添加B的通知而不崩溃......
但是要注意:添加的观察者的次数要和移除观察者的次数相等,少移除一个或者多移除一个都会造成程序崩溃:


2、 通知的使用
Model.h和Model.m

简易封装的通知中心类:Notification.h 和 Notification.m

在ViewController.m中:

输出结果:
2016-03-10 20:36:20.077 通知[28333:641372]
Hello,NSConcreteNotification 0x7fbafbd0b620 {name = A; userInfo = Hello,a}!
2016-03-10 20:36:20.078 通知[28333:641372]
Hello,NSConcreteNotification 0x7fbafbd0bca0 {name = B; userInfo = Hello,b}!
3、观察者模式
关于观察者模式,我们百度百科一下,会找到:
观察者模式(有时又被称为发布(publish )-订阅(Subscribe)模式、模型-视图(View)模式、源-收听者(Listener)模式或从属者模式)是软件设计模式的一种。在此种模式中,一个目标物件管理所有相依于它的观察者物件,并且在它本身的状态改变时主动发出通知。这通常透过呼叫各观察者所提供的方法来实现。此种模式通常被用来实现事件处理系统。

在这个图示例中,"订阅书刊的用户"需要向"书刊发行机构"提供基本的注册信息,这些信息包括用户自己的基本信息和要"订阅的书刊号",然后确定成为"
书刊发行机构"的用户,然后当"书刊发行机构"开始发行书刊,就会根据"订阅书刊的用户"的已经提供过的基本信息,进行发行书刊。然后"订阅书刊的用户"
就会得到相应的书刊。
在这个"发行-订阅"的模式中,"书刊发行机构"和"订阅书刊的用户"之间是靠"订阅书刊的用户"提供的基本有效的信息建立联系的。
这个"发行-订阅"的模式也是一种观察者模式的一个生活中非常生动的例子。"书刊发行机构"相当于观察者模式中的一个"通知中心"的角色,会根据实际需求根据用户信息向用户发送消息,然后用户作为观察者收到这些消息之后,就会自动的根据消息来执行自己的业务逻辑。
接下来,我们要实现通知中心的抽象设计
根据需求分析,首先我们需要一个唯一的"书刊发行机构",然后可以增加和删除书刊,同时能存储多个书刊,然后每个书刊又可以对应多个"订阅书刊的用户",
另外要补充一个就是,在添加和移除用户的接口中,我们需要传入用户信息对象,这个用户信息对象我们需要用协议来约束它,我们思考一下,比如订阅书刊,我
们当然需要用户最基本的两个信息,用户的ID和用户订阅的书刊号,用户的ID用于"书刊发行机构"能够准确的发消息或者发书刊正确无误的发对了人,这个作
用就好比我们唯一的身份证号码的作用是一样的。然后用户订阅的书刊号,就能保证"书刊发行机构"能把正确的书刊发到用户手中,不能随便什么书刊都发向随便
什么人的吧。
所以先写出下面所有的公开的接口,后面再具体实现它们,这就是面向接口设计:
另外,当"书刊发行机构"有了新的书刊的时候,根据需求,创建一个书刊号,然后如果有新的用户需要订阅新的书刊,根据需求,创建一个用户订阅书刊的信息对象。
一个书刊对应每个月会在某一天发布新书,当"书刊发行机构"的现有的书刊有了新的书发布的时候,就会发消息通知订阅这个书刊的用户,然后用户会做出及时的响应回馈。
按照观察者模式,被观察者发送消息,观察者收到消息就需要立马做出响应。这个和我们之前用的Cocoa框架已经实现的KVO和通知的模式是一样的。
为了实现这样的模式,我们还需要给用户信息对象用一个协议来约束它:

接着我们为上面的公开的接口具体实现,但是我们需要选择一个数据结构来存储书刊号和订阅书刊的用户信息对象,这里我选择使用NSMutableDictionary的Key-Value来存储书刊号和书刊,用NSHashTable来存储用户信息对象。
那么为什么要用NSHashTable来存储用户信息呢?为什么不用别的数据结构,比如数组(NSMutableArray)或者字典(NSMutableDictionary).
因为NSHashTable会对添加进的对象持有弱引用,当添加进来的元素,外部对他持有的强引用都取消的时候,这个对象就会自动从内存中消除,这样就不需要手动移除这些对象。
这个相比Cocoa给我们实现的KVO和通知,就不需要我们手动去操作实现removeObserve方法了。
虽然说,在使用NSHashTable实现的观察者模式,观察者对象本身就至少需要一个强引用,但是在实际开发中,观察者往往都至少会有一个强引用的。
所以,使用NSHashTable对系统算是一个小小的优化。

然后接着我们使用前面创造的观察者模式:
CustomerA.h和CustomerA.m:

在ViewController中,同时也把ViewController作为用户对象,以self传入:

打印:
2016-03-11 14:50:38.980 ObserverPattern[7958:175895] hashTable:NSHashTable {
[5] <ViewController: 0x7f93d2d26ac0>
[12] <CustomerA: 0x7f93d2c17f40>
}
2016-03-11 14:50:38.981 ObserverPattern[7958:175895] V1.0 SCIENCE
2016-03-11 14:50:38.981 ObserverPattern[7958:175895]
Hello,My Name is : CustomerA
V1.0--SCIENCE
备份的源码链接: http://pan.baidu.com/s/1eQTnm50 密码: s7su
4、自己实现KVO(以后有时间补上)
转载注明出处:http://www.cnblogs.com/goodboy-heyang/p/5265675.html ,尊重劳动成果。
本人最大的学习来源是阅读一直走在行业里很前面的大牛写的博客,有的博客还可能是一个团队写的,本人本篇深入学习的知识都是来自阅读它们的文章,中国有传统美德叫饮水思源,所以在这里也分享分享与本篇知识相关的学习资料来源(附有超链接,点击就能跳转):
1、《KVO的使用》
2、《通知中心NSNotificationCenter的使用》
3、《3种方式实现KVO并进行对比》
4、《手动设定实例变量的KVO实现监听》
5、《如何自己手动写一个KVO》
6、《需要罗列出所有的KVO的使用方法》
IOS设计模式-观察者模式的更多相关文章
- iOS设计模式和机制之观察者模式
观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象.这个主题对象在状态上发生变化时,会通知所有观察者对象,使它们能够自动更新自己. 观察者模式的思想:当某对象改变时,观察者会 ...
- iOS设计模式(01):观察者
iOS设计模式(01):观察者 iOS-Observer-Pattern 什么是观察者模式 什么是观察者模式?你曾经订阅过报纸吗?在订阅报纸的时候,你不用去任何地方,只需要将你的个人地址信息以及订阅信 ...
- IOS设计模式浅析之单例模式(Singleton)
说在前面 进入正式的设计模式交流之前,扯点闲话.我们在项目开发的过程中,经常会不经意的使用一些常见的设计模式,如单例模式.工厂方法模式.观察者模式等,以前做.NET开发的时候,认真拜读了一下程杰老师的 ...
- iOS书摘之Objective-C编程之道 iOS设计模式解析
来自<Objective-C编程之道iOS设计模式解析>一书的摘要总结 一.Prototype 原型模式 定义:使用原型实例指定创建对象的种类,并通过复制这个原型创建新的对象.(<设 ...
- iOS 设计模式
很赞的总结 iOS Design Patterns 中文版 IOS设计模式之一(MVC模式,单例模式) IOS设计模式之二(门面模式,装饰器模式) IOS设计模式之三(适配器模式,观察者模式) IOS ...
- iOS设计模式 - (1)概述
近期可自由安排的时间比較多, iOS应用方面, 没什么好点子, 就先放下, 不写了.花点时间学学设计模式. 之后将会写一系列博文, 记录设计模式学习过程. 当然, 由于我自己是搞iOS的, 所以之后设 ...
- 18. 星际争霸之php设计模式--观察者模式
题记==============================================================================本php设计模式专辑来源于博客(jymo ...
- IOS设计模式之一(MVC模式,单例模式)
iOS 设计模式-你可能已经听说过这个词,但是你真正理解它意味着什么吗?虽然大多数的开发者可能都会认为设计模式是非常重要的,然而关于设计模式这一主题的文章却不多,并且有时候我们开发者在写代码的时候也不 ...
- iOS 设计模式之工厂模式
iOS 设计模式之工厂模式 分类: 设计模式2014-02-10 18:05 11020人阅读 评论(2) 收藏 举报 ios设计模式 工厂模式我的理解是:他就是为了创建对象的 创建对象的时候,我们一 ...
随机推荐
- ab网站压力测试
ab网站压力测试命令的参数.输出结果的中文注解 permalink 以前安装好APACHE总是不知道该如何测试APACHE的性能,现在总算找到一个测试工具了.就是APACHE自带的测试工具AB( ...
- oracle11g的standby性能分析报告statpack安装
一般常见的分析standby database的性能问题的方法就是通过动态性能视图来判断,从11g开始,随着Active Data Guard功能的出现,早期的Statspack 工具可以在stand ...
- Software license key and activation
http://stackoverflow.com/questions/16222674/software-license-key-and-activationhttps://github.com/La ...
- BaaS模式的开发思路
如今,有一种BaaS服务(后端即服务)的模式,即无需编程即可生成后端应用及相应API. Drupal这套CMS下,有一款插件Services,可以在线直接自定义各种格式如json.xmlrpc.web ...
- 让禅道也可以玩BearyChat
简单的理解,BearycChat是一种IM,是一种能聚合各种MS系统消息的东西,是团队协作过程中消息流转的利器. 我是工具控,所以不折腾不舒服. 废话不说,上码: /path_to_zentao/mo ...
- Oracle数据库,模糊查询、去重查询
分组去重查询,并执行某一个函数 :select 分组字段,聚合函数 from 表名 where 条件 group by分组字段 select 分组字段,聚合函数 from 表名 where 条件 g ...
- 第 17 章 CSS 边框与背景[上]
学习要点: 1.声明边框 2.边框样式 3.圆角边框 主讲教师:李炎恢 本章主要探讨 HTML5 中 CSS 边框和背景,通过边框和背景的样式设置,给元素增加更丰富的外观. 一.声明边框 边框的声明有 ...
- NYOJ:题目490 翻译
题目链接:http://acm.nyist.net/JudgeOnline/problem.php?pid=490 这题的输入输出格式好像描述的不太清楚,1)可能是所有数据都完成输入,然后再输出(解法 ...
- windows不能显示此连接属性。windows management instrumentation (WMI) 信息可能损坏
Windows Management Instrumentation (WMI)信息可能损坏错误修复 在 查看“本地连接”的属性,并切换到“高级”选项卡后,提示:“Windows不能显示此连接的属性. ...
- JAVA JDK的动态代理反射实现
动态代理类使用到了一个接口InvocationHandler和一个代理类Proxy ,这两个类配合使用实现了动态代理的功能. 什么是动态代理呢? 普通代理类是指: 给每个具体类写一个代理类,以后要使 ...