iOS设计模式(01):观察者
iOS设计模式(01):观察者
iOS-Observer-Pattern
什么是观察者模式
什么是观察者模式?你曾经订阅过报纸吗?在订阅报纸的时候,你不用去任何地方,只需要将你的个人地址信息以及订阅信息告诉出版社,出版社就知道如何将相关报纸传递给你。这种模式的第二个名称叫做发布/订阅模式。
在GoF中是这样描述观察者模式的——观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态上发生变化时,会通知所有观察者对象,使它们能够自动更新自己。
观察者模式的的思想非常简单,Subject(主题)允许别的对象——观察者(这些对象实现了观察者接口)对这个Subject的改变进行订阅和取消订阅。当Subject发生了变化——那么Subject会将这个变化发送给所有的观察者,观察者就能对Subject的变化做出更新。在这里,Subject是报纸的出版社,而观察者则是订阅报纸的我和你,当Subject发生变化——有新的报纸,会做出通知——将报纸发送给所有的订阅者。
什么时候使用观察者模式?
- 当你需要将改变通知所有的对象时,而你又不知道这些对象的具体类型,此时就可以使用观察者模式。
- 改变发生在同一个对象中,并在别的地方需要将相关的状态进行更新。
iOS中观察者模式的实现方法
在iOS中观察者模式的实现有三种方法:
Notification
Notification - NotificationCenter机制使用了操作系统的功能。通过NSNotificationCenter可以让对象之间进行进行通讯,这些对象相互间可以不认识。当你用一个并行的流来推送通知,或者刷新数据库,并希望在界面中能够看到时,这非常有用。
NotificationCenter发布消息的方法如下所示:
NSNotification * broadcastMessage = [ NSNotification notificationWithName: AnyNotification object: Self ];
NSNotificationCenter * notificationCenter = [ NSNotificationCenter defaultCenter];
[NotificationCenter postNotification: broadCastMessage];
上面的代码中,创建了一个NSNotification类型的对象,并指定名称为”broadcastMessage”,然后通过notificationCenter来发布这个消息。
要订阅感兴趣的对象中的相关事件,可以按照如下方法进行:
NSNotificationCenter * notificationCenter = [ NSNotificationCenter defaultCenter];
[NotificationCenter addObserver: Self selector: @ selector (update:) name: AnyNotification object: nil ];
如上代码所示:订阅了一个事件,并通过@selector指定了一个方法。
// 收到通知中心发来的通知
-(void)update:(NSNotification *) notification
{
if ([[notification name] isEqualToString:AnyNotification])
NSLog (@"成功收到通知中心发来的名为%@的通知", AnyNotification);
}
下面是运行上面代码,在控制台输出的内容:
2013-05-05 23:43:15.570 ObserverPattern[1738:c07] 成功收到通知中心发来的名为broadcastMessage的通知
KVO
通过KVO,某个对象中的特定属性发生了改变,别的对象可以获得通知。苹果官方文档对KVO有了很好的解释:Key-Value
Observing Programming Guide。下面两种方法都可以改变对象中属性的值:
kvoSubj.changeableProperty = @"新的一个值"; [kvoSubj setValue:@"新的一个值" forKey:@"changeableProperty"];
上面这种值改变的灵活性可以让我们对键值进行观察。
下面是新建的一个类KVOSubject,这个类中有一个属性changeableProperty:
@interface KVOSubject : NSObject @property (nonatomic, strong) NSString *changeableProperty; @end @implementation KVOSubject @end
接着新建了另外一个类KVOObserver,通过该类可以监听changeableProperty属性值的改变。
@interface KVOObserver : NSObject
@end @implementation KVOObserver -(void) observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
NSLog(@"KVO:值发生了改变");
} @end
如上代码所示,KVOObserver类只有一个方法observeValueForKeyPath。当changeableProperty属性值的改变时,这个方法会被调用。下面是测试的代码:
- (IBAction)btnKVOObservationTest:(id)sender {
KVOSubject *kvoSubj = [[KVOSubject alloc] init];
KVOObserver *kvoObserver = [[KVOObserver alloc] init];
[kvoSubj addObserver:kvoObserver forKeyPath:@"changeableProperty"
options:NSKeyValueObservingOptionNew context:nil];
kvoSubj.changeableProperty = @"新的一个值";
[kvoSubj setValue:@"新的一个值" forKey:@"changeableProperty"];
[kvoSubj removeObserver:kvoObserver forKeyPath:@"changeableProperty"];
}
执行上面的代码,可以看到控制台输出如下结果:
2013-05-05 23:10:20.789 ObserverPattern[1358:c07] KVO:值发生了改变
2013-05-05 23:10:20.790 ObserverPattern[1358:c07] KVO:值发生了改变
标准方法
先来看看Gof中对观察者模式定义的结构图:
Observer-Structure
标准方法的实现是这样的:Subject(主题)知道所有的观察者,但是不知道它们的类型。下面我们就从创建Subject和Observer(观察者)的协议(protocol)开始。
@protocol StandardObserver
-(void) valueChanged:(NSString *)valueName newValue:(NSString *) newValue;
@end @protocol StandardSubject
-(void) addObserver:(id) observer;
-(void) removeObserver:(id) observer;
-(void) notifyObjects;
@end
下面,我们来创建一个Subject的implementation (实现)
@interface StandardSubjectImplementation : NSObject
{
@private NSString *_valueName;
@private NSString *_newValue;
}
@property (nonatomic, strong) NSMutableSet *observerCollection;
-(void)changeValue:(NSString *)valueName andValue:(NSString *) newValue;
@end @implementation StandardSubjectImplementation -(NSMutableSet *) observerCollection
{
if (_observerCollection == nil)
_observerCollection = [[NSMutableSet alloc] init]; return _observerCollection;
} -(void) addObserver:(id)observer
{
[self.observerCollection addObject:observer];
} -(void) removeObserver:(id)observer
{
[self.observerCollection removeObject:observer];
} -(void) notifyObjects
{
for (id observer in self.observerCollection) {
[observer valueChanged: _valueName newValue:_newValue];
}
} -(void)changeValue:(NSString *)valueName andValue:(NSString *) newValue
{
_newValue = newValue;
_valueName = valueName;
[self notifyObjects];
}
@end
接下来是Observer的implementation (实现):
@interface SomeSubscriber : NSObject
@end @implementation SomeSubscriber
-(void) valueChanged:(NSString *)valueName newValue:(NSString *)newValue
{
NSLog(@"SomeSubscriber输出: 值 %@ 已变为 %@", valueName, newValue);
}
@end @interface OtherSubscriber : NSObject @end @implementation OtherSubscriber -(void) valueChanged:(NSString *)valueName newValue:(NSString *)newValue
{
NSLog(@"OtherSubscriber输出: 值 %@ 已变为 %@", valueName, newValue);
}
@end
下面是演示的代码:
StandardSubjectImplementation * subj = [[StandardSubjectImplementation alloc] init];
SomeSubscriber * someSubscriber = [[SomeSubscriber alloc] init];
OtherSubscriber * otherSubscriber = [[OtherSubscriber alloc] init]; [Subj addObserver: someSubscriber];
[Subj addObserver: otherSubscriber]; [subj changeValue:@"version" andValue:@"1.0.0"];
上面代码运行的log如下所示:
2013-05-05 23:19:04.662 ObserverPattern[1459:c07] OtherSubscriber输出: 值 version 已变为 1.0.0
2013-05-05 23:19:04.664 ObserverPattern[1459:c07] SomeSubscriber输出: 值 version 已变为 1.0.0
代码实例
本文涉及到的相关实例代码和PDF归档可以到点击下图下载:
代码下载
pdf-icon
美文推荐:When
to use Delegation, Notification, or Observation in iOS
iOS设计模式(01):观察者的更多相关文章
- IOS设计模式第七篇之观察者设计模式
版权声明:原创作品,谢绝转载!否则将追究法律责任. 观察者设计模式 在观察者设计模式里面,一个对象通知其他的对象一些状态的改变.涉及这些对象不需要知道另一个对象---因此鼓励解耦设计模式.这个设计模式 ...
- IOS设计模式之一(MVC模式,单例模式)
iOS 设计模式-你可能已经听说过这个词,但是你真正理解它意味着什么吗?虽然大多数的开发者可能都会认为设计模式是非常重要的,然而关于设计模式这一主题的文章却不多,并且有时候我们开发者在写代码的时候也不 ...
- iOS 设计模式
很赞的总结 iOS Design Patterns 中文版 IOS设计模式之一(MVC模式,单例模式) IOS设计模式之二(门面模式,装饰器模式) IOS设计模式之三(适配器模式,观察者模式) IOS ...
- iOS 设计模式之工厂模式
iOS 设计模式之工厂模式 分类: 设计模式2014-02-10 18:05 11020人阅读 评论(2) 收藏 举报 ios设计模式 工厂模式我的理解是:他就是为了创建对象的 创建对象的时候,我们一 ...
- iOS设计模式之生成器
iOS设计模式之生成器 1.生成器模式的定义 (1): 将一个复杂的对象的构件与它的表示分离,使得相同的构建过程能够创建不同的表示 (2): 生成器模式除了客户之外还包括一个Director(指导者) ...
- IOS设计模式之三:MVC模式
IOS设计模式之三:MVC模式 模型-视图-控制器 这个模式其实应该叫做MCV,用控制器把model与view隔开才对,也就是model与view互相不知道对方的存在,没有任何瓜葛,他们就像一个团 ...
- iOS设计模式 - 享元
iOS设计模式 - 享元 原理图 说明 享元模式使用共享物件,用来尽可能减少内存使用量以及分享资讯给尽可能多的相似物件:它适合用于只是因重复而导致使用无法令人接受的大量内存的大量物件.通常物件中的部分 ...
- iOS设计模式 - 责任链
iOS设计模式 - 责任链 原理图 说明 在责任链模式里,很多对象由每一个对象对其下家的引用而连接起来形成一条链.请求在这个链上传递,直到链上的某一个对象决定处理此请求.发出这个请求的客户端并不知道链 ...
- iOS设计模式 - 模板
iOS设计模式 - 模板 原理图 说明 定义一个操作中的算法的骨架,而将步骤延迟到子类中.模板方法使得子类可以不改变一个算法的结构即可重定义算法的某些特定步骤. 源码 https://github.c ...
随机推荐
- WPF 中使用附加属性,将任意 UI 元素或控件裁剪成圆形(椭圆)
不知从什么时候开始,头像流行使用圆形了,于是各个平台开始追逐显示圆形裁剪图像的技术.WPF 作为一个优秀的 UI 框架,当然有其内建的机制支持这种圆形裁剪. 不过,内建的机制仅支持画刷,而如果被裁剪的 ...
- Distributed Denial of Service
Distributed Denial of Service https://www.cnblogs.com/163yun/p/10030890.html 全称Distributed Denial of ...
- python函数参数总结
python中函数参数有:默认参数.关键字参数.非关键字可变长参数(元组).关键字可变长参数(字典) 默认参数:在函数声明时,指定形参的默认值,调用时可不传入改参数(使用默认值)def foo(x): ...
- thinkphp 使每一个模板页都包括一个header文件和一个footer文件
在开发的过程中,常常遇到要使每一个模板页都包括一个header文件和一个footer文件.thinkPHP的模板布局为我们提供了一个叫全局配置方式可以解决问题. 1. 在配置文件里开启LAYOUT_O ...
- centos安装 node.js
curl --silent --location https://rpm.nodesource.com/setup_8.x | sudo bash - yum clean all yum makeca ...
- git 清除本地无效的分支
远程服务器的分支已经删掉了,但是本地分支还存在 $ git fetch -p 如果不行,使用下面的指令 $ git remote prune origin
- WPF ComboBox下拉绑定Treeview 功能的实现
因为项目需要,接触到这个功能点,借助网络还有自己的一点摸索,实现了这个功能.相关代码如下: XAML部分的代码: <ComboBox Grid.Row=" RenderTransfor ...
- Windows Restart Manager 重启管理器
Restart Manager(以下简称RM)可以减少或避免安装或更新程序所需要的系统重启次数.安装(或更新)过程中需要重启的主要原因是需要更新的某些文件当前正被一些其它程序或服务所使用.RM允许除关 ...
- [转]SQL Server 结构读取
本文来自:http://www.cnblogs.com/StrangeCity/p/4352753.html -- 本文来自:http://www.cnblogs.com/StrangeCity/p/ ...
- Mysql无法创建外键的原因 !!!
在MySQL中创建外键时,经常会遇到问题而失败,这是因为Mysql中还有很多细节需要我们去留意,我自己总结并查阅资料后列出了以下几种常见原因. 1. 两个字段的类型或者大小不严格匹配.例如,如果一个 ...