观察者模式容许一个对象在它的状态发生变化时通知多个观察者,而被观察的对象无需对观察者有特定的认识。观察者模式在cocoa中以多种形式出现,包括NSNotification、委托观察遗迹键-值观察(kvo)。他促使对象之间产生弱藕合,以使组建更具可重用性而且更加健壮。app
大多数cocoa开发者都遇到过NSNotificationCenter ,它容许经过一个对象注册被通知的事件来提供松散耦合,该事件被字符串名称定义,通知比kvo更容易理解和实现,下面是关于如何使用它的多示例。异步
//Poster.h //为通知定义一个字符串常量 //注意这样是声明一个指向不可变字符串的常量指针 extern NSString *const PosterDidSomethingNotificaton;
//Poster.m NSString *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的值无关。)post
屡次使用相同参数调用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]]){ /* *... */ } }
这种方法下降了观察的数量,但在回调过程当中添加了一个额外的检查。code
发生通知时同步的,这可能会让那些但愿在另外一个线程上执行通知货其余方式异步运行通知的开发者感到不便,server