前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Objective-C 观察者模式--简单介绍和使用

Objective-C 观察者模式--简单介绍和使用

作者头像
周希
发布2019-10-15 14:37:03
3710
发布2019-10-15 14:37:03
举报
文章被收录于专栏:APP自动化测试APP自动化测试

观察者模式(有时又被称为发布-订阅模式)

在此种模式中,一个目标物件管理所有相依于它的观察者物件,并且在它本身的状态改变时主动发出通知。

这通常透过呼叫各观察者所提供的方法来实现。此种模式通常被用来实现事件处理系统。

比如我们订阅杂志, 会有一个订阅服务中心, 他负责管理期刊号, 添加用户 和 发送期刊

这里订阅服务中, 期刊, 用户 我们看做3个因素:

用户要订阅, 需要遵循一定的订阅规范(协议)

期刊要能记录有哪些订阅用户

订阅服务中心负责管理, 当有某一期刊更新时, 通知该期刊的订阅用户或者发送新期刊给订阅用户

下面我们依照这个思路构造工程

这里把订阅服务中心看做一个对象, 并把它设计成一个单例 因为一般只会有一个订阅服务中心管理所有的期刊和用户

订阅服务中心对象有以下功能:

添加/删除期刊, 给某一期刊添加/删除订阅用户, 检查期刊号是否存在, 当有更新时通知订阅用户

期刊管理订阅用户信息时, 不能持有订阅用户对象造成内存泄露, 所以用NSHashTable来保存用户信息

用户要遵守一个订阅规范(协议)

SubscriptionCustomerProtocol.h

代码语言:javascript
复制
1 #import <Foundation/Foundation.h>
2 
3 @protocol SubscriptionCustomerProtocol <NSObject>
4 
5 @required
6 - (void)subscriptionMessage:(id)message subscriptionNumber:(NSString *)subscriptionNumber;
7 
8 @end

下面构造订阅服务中心对象-用单例模式

SubscriptionServiceCenter.h

代码语言:javascript
复制
 1 #import <UIKit/UIKit.h>
 2 #import "SubscriptionCustomerProtocol.h"
 3 
 4 @interface SubscriptionServiceCenter : NSObject
 5 
 6 /**
 7  初始化单例方法
 8 
 9  @return 返回单例对象
10  */
11 + (instancetype)shareInstance;
12 
13 /**
14  alloc初始化方法
15 
16  @param zone 地址空间
17  @return 返回单例对象
18  */
19 + (id)allocWithZone:(struct _NSZone *)zone;
20 
21 /**
22  copy方法
23 
24  @param zone 地址空间
25  @return 返回单例对象
26  */
27 - (id)copWithZone:(struct _NSZone *)zone;
28 
29 #pragma mark - 维护订阅信息
30 /**
31  创建订阅号
32 
33  @param subscriptionNumber 订阅号码
34  */
35 - (void)createSubscriptionNumber:(NSString *)subscriptionNumber;
36 
37 /**
38  删除订阅号
39 
40  @param subscriptionNumber 订阅号码
41  */
42 - (void)removeSubscriptionNUmber:(NSString *)subscriptionNumber;
43 
44 #pragma mark - 维护客户信息
45 /**
46  添加客户到具体的订阅号中
47 
48  @param customer 客户
49  @param subscriptionNumber 订阅号码
50  */
51 - (void)addCustomer:(id <SubscriptionCustomerProtocol>)customer withSubscriptionNumber:(NSString *)subscriptionNumber;
52 
53 /**
54  从具体订阅号中移除客户
55 
56  @param customer 客户
57  @param subscriptionNumber 订阅号码
58  */
59 - (void)removeCustomer:(id <SubscriptionCustomerProtocol>)customer withSubcriptionNumber:(NSString *)subscriptionNumber;
60 
61 /**
62  发送消息到具体的订阅号中
63 
64  @param message 消息
65  @param subscriptionNumber 订阅号码
66  */
67 - (void)sendMessage:(id)message toSubscriptionNumber:(NSString *)subscriptionNumber;
68 
69 /**
70  获取用户列表
71 
72  @param subscriptionNumber 订阅号码
73  @return 返回用户列表
74  */
75 - (NSHashTable *)existSubscriptionNumber:(NSString *)subscriptionNumber;
76 
77 @end

SubscriptionServiceCenter.m

代码语言:javascript
复制
 1 #import "SubscriptionServiceCenter.h"
 2 
 3 static NSMutableDictionary *_subscriptionDictionary = nil;
 4 
 5 @implementation SubscriptionServiceCenter
 6 
 7 static SubscriptionServiceCenter *_instance = nil;
 8 
 9 + (instancetype)shareInstance {
10     
11     static dispatch_once_t onceToken;
12     dispatch_once(&onceToken, ^{
13         _subscriptionDictionary = [NSMutableDictionary dictionary];
14         _instance = [[super allocWithZone:NULL] init];
15     });
16     
17     return _instance;
18 }
19 
20 + (id)allocWithZone:(struct _NSZone *)zone {
21     
22     return [SubscriptionServiceCenter shareInstance];
23 }
24 
25 - (id)copWithZone:(struct _NSZone *)zone {
26     
27     return [SubscriptionServiceCenter shareInstance];
28 }
29 
30 - (void)createSubscriptionNumber:(NSString *)subscriptionNumber {
31     
32     NSParameterAssert(subscriptionNumber);
33     
34     NSHashTable *hashTable = [self existSubscriptionNumber:subscriptionNumber];
35     if (hashTable == nil) {
36         
37         hashTable = [NSHashTable weakObjectsHashTable];
38         [_subscriptionDictionary setObject:hashTable forKey:subscriptionNumber];
39     }
40 }
41 
42 - (void)removeSubscriptionNUmber:(NSString *)subscriptionNumber {
43     
44     NSParameterAssert(subscriptionNumber);
45     
46     NSHashTable *hashTable = [self existSubscriptionNumber:subscriptionNumber];
47     if (hashTable) {
48         
49         [_subscriptionDictionary removeObjectForKey:subscriptionNumber];
50     }
51 }
52 
53 - (void)addCustomer:(id <SubscriptionCustomerProtocol>)customer withSubscriptionNumber:(NSString *)subscriptionNumber {
54     
55     NSParameterAssert(customer);
56     NSParameterAssert(subscriptionNumber);
57     
58     NSHashTable *hashTable = [self existSubscriptionNumber:subscriptionNumber];
59     [hashTable addObject:customer];
60 }
61 
62 - (void)removeCustomer:(id <SubscriptionCustomerProtocol>)customer withSubcriptionNumber:(NSString *)subscriptionNumber {
63     
64     NSParameterAssert(subscriptionNumber);
65     
66     NSHashTable *hashTable = [self existSubscriptionNumber:subscriptionNumber];
67     [hashTable removeObject:customer];
68 }
69 
70 - (void)sendMessage:(id)message toSubscriptionNumber:(NSString *)subscriptionNumber {
71 
72     NSParameterAssert(subscriptionNumber);
73     
74     NSHashTable *hashTable = [self existSubscriptionNumber:subscriptionNumber];
75     if (hashTable) {
76 
77         NSEnumerator *enumerator = [hashTable objectEnumerator];
78         id <SubscriptionCustomerProtocol> object = nil;
79         while (object = [enumerator nextObject]) {
80 
81             if ([object respondsToSelector:@selector(subscriptionMessage: subscriptionNumber:)]) {
82 
83                 [object subscriptionMessage:message subscriptionNumber:subscriptionNumber];
84             }
85         }
86     }
87 }
88 
89 - (NSHashTable *)existSubscriptionNumber:(NSString *)subscriptionNumber {
90     
91     return [_subscriptionDictionary objectForKey:subscriptionNumber];
92 }
93 
94 @end

下面在Controller中实现, Controller作为用户即观察者

代码语言:javascript
复制
 1 #import "ViewController.h"
 2 #import "SubscriptionCustomerProtocol.h"
 3 #import "SubscriptionServiceCenter.h"
 4 
 5 static NSString * SCIENCE = @"SCIENCE";
 6 
 7 @interface ViewController () <SubscriptionCustomerProtocol>
 8 
 9 @end
10 
11 @implementation ViewController
12 
13 - (void)viewDidLoad {
14     [super viewDidLoad];
15     
16     //创建一个订阅服务中心单例
17     SubscriptionServiceCenter *center = [SubscriptionServiceCenter shareInstance];
18     
19     //创建一个订阅号
20     [center createSubscriptionNumber:SCIENCE];
21     
22     //添加一个用户
23     [center addCustomer:self withSubscriptionNumber:SCIENCE];
24     
25     //发送一个通知消息
26     [center sendMessage:@"有新的期刊啦" toSubscriptionNumber:SCIENCE];
27     
28 }
29 
30 #pragma mark - SubscriptionCustomerProtocol
31 - (void)subscriptionMessage:(id)message subscriptionNumber:(NSString *)subscriptionNumber {
32     
33     NSLog(@"期刊号: %@ 收到消息: %@", subscriptionNumber, message);
34 }
35 
36 
37 @end

Cocoa touch中的KVO和NSNotificationCenter的原理是观察模式的很好实现, 下面用代码分别演示下用法

KVO的用法

代码语言:javascript
复制
 1 - (void)viewDidLoad {
 2     [super viewDidLoad];
 3     // Do any additional setup after loading the view, typically from a nib.
 4 
 5     self.model = [Model new];
 6     
 7     //添加KVO
 8     [self.model addObserver:self
 9                  forKeyPath:@"name"
10                     options:NSKeyValueObservingOptionNew
11                     context:nil];
12     
13     //发送信息, 通过修改属性
14     self.model.name = @"v1.0";
15      
16 }
17 
18 #pragma mark - KVO方法
19 - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context {
20     NSLog(@"%@", change);
21 }
22 
23 - (void)dealloc {
24 
25     //移除KVO
26     [self.model removeObserver:self
27                     forKeyPath:@"name"];
28 }

NSNotificationCenter的用法

代码语言:javascript
复制
 1 - (void)viewDidLoad {
 2     [super viewDidLoad];
 3     // Do any additional setup after loading the view, typically from a nib.
 4     
 5     //添加
 6     [[NSNotificationCenter defaultCenter] addObserver:self
 7                                              selector:@selector(notificationCenterEvent:)
 8                                                  name:@"SCIENCE"
 9                                                object:nil];
10     
11     //发送信息
12     [[NSNotificationCenter defaultCenter] postNotificationName:@"SCIENCE"
13                                                         object:@"v1.0"];
14     
15 }
16 
17 #pragma mark - 通知中心方法
18 - (void)notificationCenterEvent:(id)sender {
19     NSLog(@"%@", sender);
20 }
21 
22 - (void)dealloc {
23     //移除通知中心
24     [[NSNotificationCenter defaultCenter] removeObserver:self
25                                               forKeyPath:@"SCIENCE"];
26 
27 }
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2016-11-05 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档