设计模式深入学习IOS版(7)观察者模式

来源:互联网 发布:晋业医药软件 编辑:程序博客网 时间:2024/06/16 09:26

1 前言

  观察者(Observer)模式也叫发布/订阅(Publish/Subscribe)模式,是MVC(模型-视图-控制器)模式的重要组成部分。在IOS的Cocoa Touch里面也有的广泛的应用,今天我们就来学习一下这个模式。

  转载请注明出处:http://blog.csdn.net/developer_zhang

2 详述

  该模式使用来解决一个对象状态改变连带影响到其他对象的状态发生改变的情景的。而且复用性强,可以做到对象之间匿名通信。

2.1 实现原理

  观察者模式的类图如下:


图中4个角色:

抽象主题(Subject):在Object-C中,抽象主题是一个协议,它是一个观察者集合容器,定义了增加观察者(attach)方法,移除观察者(detach)方法和为所有观察者发送通知的方法(notifyObserver)。

具体主题:Subject协议的具体实现。

抽象观察者(Observer):抽象观察者是一个协议,他是一个更新(update)方法。

具体观察者(ConcreteObserver):Observer的具体实现。

引入了Subject和Observer这两个协议后,不仅提高了系统的可复用性,还降低了耦合度。

代码实现:

抽象主题协议:

#import <Foundation/Foundation.h>@class Observer;/*! *  抽象主题协议 * *  @since V1.0 */@protocol Subject <NSObject>@required/*! *  增加观察者 * *  @param observer 观察者实例 * *  @since V1.0 */-(void)attach:(Observer*) observer;/*! *  移除观察者 * *  @param observer 观察者实例 * *  @since V1.0 */-(void)detach:(Observer*) observer;/*! *  为观察者发送通知 * *  @since V1.0 */-(void)notifyObservers;@end


观察者协议:

#import <Foundation/Foundation.h>/*! *  观察者协议 * *  @since V1.0 */@protocol Observer <NSObject>@required-(void)update;@end


具体的观察者类:

#import <Foundation/Foundation.h>#import "Observer.h"/*! *  具体的观察者类 * *  @since V1.0 */@interface ConcreteObserver : NSObject<Observer>@end


具体主题类:

#import <Foundation/Foundation.h>#import "Subject.h"/*! *  具体主题类 * *  @since V1.0 */@interface ConcreteSubject : NSObject<Subject>{    NSMutableArray *observers;}@property(nonatomic,strong)NSMutableArray* observers;/*! *  单例构建自身对象 * *  @return 自身对象 * *  @since V1.0 */+(ConcreteSubject*)shareConcreteSubject;@end


2.2 Cocoa Touch中的观察者模式的应用(通知机制和KVO)

  通知机制与委托机制不同的是,前者是“一对多”的对象之间的通信,后者是“一对一”的对象之间的通信。

2.2.1 通知机制

  IOS中,通知分为广播通知(broadcast notification),本地通知(localnotification)和推送通知(push notification),本节主要介绍的广播通知。它是Cocoa Touch框架中实现观察者模式的一种机制,它可以在一个应用内部的多个对象之间发送消息;本地通知和推送通知中的“通知”是给用户一种“提示”。

  如图:

  通知机制中对某个感兴趣的所有对象都可以成为接受者。首先,需要对象向通知中心(NSNotificationCenter)发出addObserver:selector:name:object:消息进行注册,在投送对象投送通知给消息中心时,通知中心会把通知广播给注册过的接收者。所有的接收者都不知道是谁投送的,更不关心它的细节。投送对象与接收者是一对多关系。接收者如果对通知不再关注,会给通知中心发出removeObserver:name:object:消息解除注册,以后不再接收通知。

代码实例:

下面我们模拟一下,应用退出后发送给视图通知的例子,类图如下:

对于注册通知中的通知的类图如下:

其中name是名字,object是投送通知时传过来的对象,userInfo是投送通知时定义的字典对象。


我们也可以把通知中的名字@“AppWillDidEnterBackgroundNotification“修改为UIApplicationDidEnterBackgroundNotification来替代,可以起到相同效果,但是不会有userInfo参数传入。

AppDelegate:

- (void)applicationDidEnterBackground:(UIApplication *)application{    // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.     // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.    NSDate* date = [NSDatedate];    NSDictionary* dataDict = [NSDictionarydictionaryWithObject:date forKey:@"DidEnterBackgroundDate"];    [[NSNotificationCenterdefaultCenter] postNotificationName:@"AppWillDidEnterBackgroundNotification"object:selfuserInfo:dataDict];}


MainViewController.m:

#import "MainViewController.h"@interface MainViewController ()@end@implementation MainViewController- (void)viewDidLoad{    [superviewDidLoad];// Do any additional setup after loading the view, typically from a nib.    //注册通知//    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleTerminate:) name:@"AppWillDidEnterBackgroundNotification" object:nil];    [[NSNotificationCenterdefaultCenter] addObserver:selfselector:@selector(handleTerminate:)name:UIApplicationDidEnterBackgroundNotificationobject:nil];}#pragma mark -处理通知-(void)handleTerminate:(NSNotification*)notification{    NSDictionary* theData = [notification userInfo];    if (theData!=nil) {        NSDate *date = [theData objectForKey:@"DidEnterBackgroundDate"];        NSLog(@"MainViewController App DidEnterBackground Date:%@",date);    }else{        NSLog(@"MainViewController App DidEnterBackground by UIApplication");    }}-(void)dealloc{    //移除通知    [[NSNotificationCenterdefaultCenter] removeObserver:self];}


2.2.2 KVO(KEY-VALUE-OBSERVERING)

  KVO不想通知机制那样通过一个通知中心通知所有观察者对象,而是在对象属性变化时通知会被直接发送给观察者对象。图为KVO机制解析图。

 可以看到,属性发生变化的对象需要发出消息addObserver:forKeyPath:options:context:给注册观察者,使观察者关注她得某个属性的变化。当对象属性变化时,观察者会接收到通知,观察者需要重写方法observeValueForKeyPath:ofObject:change:context:以响应属性变化。

App状态观察者:

#import <Foundation/Foundation.h>/*! *  App状态观察者 * *  @since V1.0 */@interface AppStatusWatcher : NSObject@end


AppStatusWatcher.m:

#import "AppStatusWatcher.h"@implementation AppStatusWatcher-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context{    NSLog(@"Property '%@' of object '%@' changed: %@ context: %@ ",keyPath,object,change,context);}@end


AppDelegate.h:

#import <UIKit/UIKit.h>#import "AppStatusWatcher.h"@interface AppDelegate : UIResponder <UIApplicationDelegate>@property (strong, nonatomic) UIWindow *window;//应用状态@property (strong, nonatomic) NSString *appStatus;//应用状态观察者@property (strong, nonatomic) AppStatusWatcher *watcher;@end


AppDelegate.m:

#import "AppDelegate.h"@implementation AppDelegate- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{    // Override point for customization after application launch.    self.watcher = [AppStatusWatcher new];    //添加注册观察    [self addObserver:self.watcher forKeyPath:@"appStatus" options:NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld context:@"Pass context"];    self.appStatus = @"launch";        return YES;}/*! *  即将不活跃 * *  @param application UIApplication * *  @since V1.0 */- (void)applicationWillResignActive:(UIApplication *)application{    // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.    // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.    self.appStatus = @"inactive";}/*! *  进入后台 * *  @param application UIApplication * *  @since V1.0 */- (void)applicationDidEnterBackground:(UIApplication *)application{    // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.     // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.    self.appStatus = @"background";}/*! *  即将进入前台 * *  @param application UIApplication * *  @since V1.0 */- (void)applicationWillEnterForeground:(UIApplication *)application{    // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.    self.appStatus = @"inactive";}/*! *  变为活动状态 * *  @param application UIApplication * *  @since V1.0 */- (void)applicationDidBecomeActive:(UIApplication *)application{    // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.    self.appStatus = @"active";}/*! *  即将被打断 * *  @param application UIApplication * *  @since V1.0 */- (void)applicationWillTerminate:(UIApplication *)application{    // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.    self.appStatus = @"teminate";}

3 结语

  以上是所有内容,希望对大家有所帮助。

  代码下载地址:

  http://download.csdn.net/detail/u010013695/6959029

  http://download.csdn.net/detail/u010013695/6965217

  http://download.csdn.net/detail/u010013695/6965961


2 0
原创粉丝点击