观察者模式允许一个对象在它的状态发生变化时通知多个观察者,而被观察的对象无需对观察者有特定的认识。观察者模式在cocoa中以多种形式出现,包括NSNotification、委托观察遗迹键-值观察(kvo)。他促使对象之间产生弱藕合,以使组建更具可重用性并且更加健壮。
大多数cocoa开发者都遇到过NSNotificationCenter ,它允许通过一个对象注册被通知的事件来提供松散耦合,该事件被字符串名称定义,通知比kvo更容易理解和实现,下面是关于如何使用它的多示例。
//Poster.h//为通知定义一个字符串常量//注意这样是声明一个指向不可变字符串的常量指针extern NSString *const PosterDidSomethingNotificaton;
//Poster.mNSString *const PosterDidSomethingNotificaton=@"PosterDidSomethingNotificaton";/**...*///其中的发送者作为通知的对象[[NSNotificationCenter defaultCenter] postNotificationName:PosterDidSomethingNotificaton object:nil];
Observe.m//导入Poster.h以获取字符串常量#import "Poster.h"//...//注册以接收通知[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(PosterDidSomething:) name: PosterDidSomethingNotificaton object:nil];...-(void)PosterDidSomething{ //在这里处理通知}-(void)dealloc{ //总是在这里移除你的观察者 [[NSNotificationCenter defaultCenter] removeObserver:self]; [super dealloc];}
观察者应该考虑是否要观察一个特定的对象活着nil(所有具有给定名称的通知,与object的值无关。)
多次使用相同参数调用addObserver:selector:name:object: 方法会导致收到多个回调,但这些回调几乎不是你想要的,一般来说最简答方法是在init理开始观察通知并在dealloc里停止,但如果你想要查看来自某个属性的通知,而这个属性可变呢?下面的示例演示如何编写setPoster:方法方便正确的为poster属性添加或者益处观察者:
-(void)setPoster:(Poster *) aPoster{ NSNotificationCenter *nc=[NSNotificationCenter defaultCenter]; if(_poster!=nil){ //针对旧值益处所有观察者 [nc removeOberver:self name:nil object:_poster]; } _poster=aPoster; if(_poster!=nil){ [nc addObserver:self selecter:@selecter(anEventDidHappen:) name:PosterDidSomethingNotification object:_poster]; }}//这里设置nil非常重要,把nil作为object或者name传递的意思是“任何对象/通知”。
要是你想观察来自大量对象的某个通知但不一定每个对象都会发生通知又改怎么办呢?比如你可能喜欢随意切换歌曲,但仅限于当前播放列表里的歌曲。你可以一首首的听,但这样非常繁琐,下面展示一种观察nil并且检查你真正想要毁掉的好方法。
//观察所有对象,无论是否在你的曲目列表中[[NSNotificationCenter defaultCenter] addOberver:self selector:@selector(trackaDidChange:) name:TrackDidChangeNotification object:nil];//...-(void)trackaDidChange{//确认这首歌曲不是你想听的if([self.tracks containsObject: [note object]]){ /* *... */ }}
这种方法降低了观察的数量,但在回调过程中添加了一个额外的检查。
发生通知时同步的,这可能会让那些希望在另一个线程上执行通知货其他方式异步运行通知的开发者感到不便,