觀察者模式也叫發(fā)布/訂閱模式,是軟件設(shè)計(jì)模式中的一種诗芜。在這種模式中衡瓶,一個(gè)目標(biāo)物件管理所有相依于它的觀察者物件舌劳,并且在它本身的狀態(tài)改變時(shí)主動(dòng)發(fā)出通知。這通常透過呼叫各觀察者所提供的方法來實(shí)現(xiàn)。此種模式通常被用來實(shí)現(xiàn)事件處理系統(tǒng)盆赤。
觀察者模式的類圖如下:
可以看出它有四個(gè)角色贾富,具體如下:
抽象主題(Subject):抽象主題是一個(gè)協(xié)議,它是一個(gè)觀察者的集合容器牺六,定義添加觀察者(attach)方法颤枪,移除觀察者(detach)方法和所有觀察者發(fā)送通知的方法(notifyObserve)。
抽象觀察者(Observe):抽象觀察者也是一個(gè)協(xié)議淑际,它有一個(gè)更新(update)方法畏纲。
具體觀察者(ConcreteObserve):觀察協(xié)議具體實(shí)現(xiàn)。
具體主題(ConcerteSubject):主題協(xié)議的具體實(shí)現(xiàn)春缕。
從圖中可以看出盗胀,引入Observe和Subject這兩個(gè)協(xié)議后,觀察者模式可以完美的將觀察者和被觀察的對(duì)象分離開锄贼,不僅提高了系統(tǒng)的可復(fù)用行票灰,還降低了耦合度。
在Cocoa Touch框架中宅荤,觀察者模式的具體應(yīng)用有兩個(gè) - 通知(notification)機(jī)制和KVO(Key-ValueObserving)機(jī)制屑迂。
通知機(jī)制
通知機(jī)制與委托機(jī)制不同的是,前者是“一對(duì)多”的對(duì)象之間的通信冯键,后者是“一對(duì)一”的對(duì)象之間的通信惹盼。
在通知機(jī)制中對(duì)某個(gè)通知感興趣的所有對(duì)象可以成為接收者首先,對(duì)這些對(duì)象需要向通知中心(NSNotificationCenter)發(fā)出addObserve:選擇器:名稱:對(duì)象消息進(jìn)行注冊(cè)惫确,在投送對(duì)象投送通知給通知中新世手报,通知中心就會(huì)把通知廣播給注冊(cè)過的接收者。所有的接收者都不知道是誰投送的改化,更不關(guān)心細(xì)節(jié)掩蛤。投送對(duì)象與接收者是一對(duì)多的關(guān)系。接收者如果對(duì)通知不再關(guān)注陈肛,會(huì)給通知中心發(fā)出removeObserver:名稱:對(duì)象:消息解除注冊(cè)揍鸟,以后不再接收通知。
注冊(cè)通知:
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = [UIColor whiteColor];
[[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(resignNotification:) name:@"login" object:nil];
/** 換種方式 */
__weak typeof(self) weakSelf = self;
[[NSNotificationCenter defaultCenter]addObserverForName:@"drain" object:nil queue:[NSOperationQueue new] usingBlock:^(NSNotification * _Nonnull note) {
NSLog(@"你瞅啥");
NSLog(@"接收到通知:%@",[NSThread currentThread]);
}];
}
-(void)resignNotification:(NSNotification *)notification{
NSLog(@"%s",__func__);
NSLog(@"接收到通知:%@",[NSThread currentThread]);
}
發(fā)送同步通知:
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
[[NSNotificationCenter defaultCenter]postNotificationName:@"login" object:nil userInfo:@{}];
}
發(fā)送異步通知:
/**
* NSPostingStyle有三種:
NSPostNow:與postNotificationName相同(就是在哪個(gè)線程里面就是獲取當(dāng)前線程的通知隊(duì)列并且默認(rèn)采用NSPostNow發(fā)送時(shí)機(jī))
NSPostASAP:不立即發(fā)出通知燥爷,而是在runloop匹配時(shí)調(diào)用蜈亩,即:runloop處理事件源時(shí)
NSPostWhenIdle:runloop閑置的時(shí)候post,即:runloop進(jìn)入睡眠時(shí)
*/
/*
NSNotificationCoalescing消息合并的方式
NSNotificationNoCoalescing = 0, //不合并
NSNotificationCoalescingOnName = 1,//按名稱合并
NSNotificationCoalescingOnSender = 2,//按發(fā)送者合并
*/
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
//每個(gè)線程都默認(rèn)又一個(gè)通知隊(duì)列前翎,可以直接獲取稚配,也可以alloc
NSNotificationQueue *notificationQueue = [NSNotificationQueue defaultQueue];
NSNotification *notification = [NSNotification notificationWithName:@"drain" object:nil];
NSNotification * notificationtwo = [NSNotification notificationWithName:@"drain" object:nil];
NSLog(@"發(fā)送通知before:%@",[NSThread currentThread]);
[notificationQueue enqueueNotification:notification postingStyle:NSPostNow coalesceMask:NSNotificationNoCoalescing forModes:nil];
[notificationQueue enqueueNotification:notificationtwo postingStyle:NSPostWhenIdle coalesceMask:NSNotificationCoalescingOnName forModes:nil];
[notificationQueue enqueueNotification:notification postingStyle:NSPostWhenIdle coalesceMask:NSNotificationCoalescingOnName forModes:nil];
NSLog(@"發(fā)送通知After:%@",[NSThread currentThread]);
}
移除通知:
[[NSNotificationCenter defaultCenter]removeObserver:self name:@"login" object:nil];
//<# #>就是<## >
輸出結(jié)果:
2018-08-22 15:20:53.382286+0800 AngelClient[4074:168069] -[ViewController resignNotification:]
2018-08-22 15:20:53.382421+0800 AngelClient[4074:168069] 接收到通知:<NSThread: 0x60c0000788c0>{number = 1, name = main}
2018-08-22 15:20:53.382513+0800 AngelClient[4074:168069] 發(fā)送通知before:<NSThread: 0x60c0000788c0>{number = 1, name = main}
2018-08-22 15:20:53.382889+0800 AngelClient[4074:168112] 你瞅啥
2018-08-22 15:20:53.383015+0800 AngelClient[4074:168112] 接收到通知:<NSThread: 0x604000267dc0>{number = 3, name = (null)}
2018-08-22 15:20:53.383172+0800 AngelClient[4074:168069] 發(fā)送通知After:<NSThread: 0x60c0000788c0>{number = 1, name = main}
2018-08-22 15:20:53.383594+0800 AngelClient[4074:168112] 你瞅啥
2018-08-22 15:20:53.383741+0800 AngelClient[4074:168112] 接收到通知:<NSThread: 0x604000267dc0>{number = 3, name = (null)}
NSNotificationCenter是單例模式,創(chuàng)建獲得共享實(shí)例的方法defaultCenter港华。其中名稱是通知的名字道川,對(duì)象是投送通知時(shí)傳遞過來的對(duì)象(不一定是self對(duì)象,如果接收者不需要,可以將其設(shè)為nil )冒萄,USERINFO是投送通知時(shí)定義的字典對(duì)象臊岸,可以用于參數(shù)的傳遞,進(jìn)行的是同步發(fā)送.NSNotificationQueue是將發(fā)送的通知加到當(dāng)前線程的隊(duì)列中尊流,進(jìn)行異步發(fā)送帅戒。
下一篇:觀察者模式-KVO詳解