觀察者設計模式詳解 基本概念 NSNotificationCenter的使用 添加監聽 接收消息 刪除監視 KVO的使用 基本概念 注冊觀察者 觀察者對象發生變化時的回調方法 remove觀察者身份 代碼實現
觀察者模式定義了一種一對多的依賴關系,讓多個觀察者對象同時監聽某一個主題對象。這個主題對象在狀態發生變化時,會通知所有觀察者對象,使它們能夠自動更新自己.而在IOS開發中我們可能會接觸到的經典觀察者模式的實現方式,有這麼幾種:NSNotificationCenter、KVO、Delegate等
KVO,即:Key-Value Observing,它提供一種機制,當指定的對象的屬性被修改後,則對象就會接受到通知。該方法與NSNotification有很大的不同,它並不需要一個NotificationCenter來為所有觀察者提供變化通知,相反的是,當有變化發生時,該通知直接發送給觀察者,NSObject為我們實現了此方法。
利用此方法我們可以觀察對象,是一種一對多的關系。
首先必須發送一個
addObserver:selfforKeyPath:@”happyNum” options:NSKeyValueObservingOptionNew |NSKeyValueObservingOptionOld
context:nil]消息至觀察對象,用以傳送觀察對象和需要觀察的屬性的關鍵路徑,參數分析:
- (void)addObserver:(NSObject )observer forKeyPath:(NSString )keyPath options:(NSKeyValueObservingOptions)options context:(void *)context;
observer:表示觀察者是誰,一般為self
keyPath: 表示觀察哪個對象
options:NSKeyValueObservingOptionNew表示觀察新值,NSKeyValueObservingOptionOld表示觀察舊值
context:表示上下文環境
(void)observeValueForKeyPath:(NSString *)keyPath
ofObject:(id)object
change:(NSDictionary *)change
context:(void *)context {
NSLog(@”%@”,change);
}
參數分析:
change:表示發生改變時返回的值
keyPath:表示觀察對象
contenst:表示上下文
發送一條制定觀察方對象和路徑來移除觀察者,該函數一般放在dealloc:
[self.childremoveObserver:selfforKeyPath:@”happyNum”context:nil];
child.h
#import
@interface Child : NSObject
@property(nonatomic,assign)NSInteger happyNum;
@end
child.m
#import "Child.h"
@implementation Child
-(id)init
{
self=[super init];
if(self)
{
self.happyNum=100;
[NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(decrease:) userInfo:nil repeats:YES];
}
return self;
}
-(void)decrease:(NSTimer*)timer
{
// NSLog(@"the happyNum is %ld",self.happyNum);
_happyNum--;
// [self setValue:[NSNumber numberWithInteger:_happyNum] forKey:@"happyNum"];
}
@end
nurse.h
#import
#import "Child.h"
@interface Nurse : NSObject
@property(nonatomic,retain)Child *child;
-(id)initWithChild:(Child*)child;
@end
nurse.m:
#import "Nurse.h"
@implementation Nurse
-(id)initWithChild:(Child*)child
{
self=[super init];
if(self)
{
self.child = child;
[self.child addObserver:self forKeyPath:@"happyNum"
options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld
context:nil];
}
return self;
}
- (void)observeValueForKeyPath:(NSString *)keyPath
ofObject:(id)object
change:(NSDictionary *)change
context:(void *)context {
NSLog(@"%@",change);
}
-(void)dealloc
{
[self.child removeObserver:self forKeyPath:@"happyNum" context:nil];
[_child release];
[super dealloc];
}
@end
main.m:
#import
#import "Child.h"
#import "Nurse.h"
int main(int argc, const char * argv[])
{
@autoreleasepool {
Child *childObj=[[[Child alloc] init] autorelease];
Nurse *nurseObj=[[[Nurse alloc] initWithChild:childObj] autorelease];
[[NSRunLoop currentRunLoop] run];
//[nurseObj release];
}
return 0;
}