1. 定義一個方法
-(void) update{ }
2. 對象註冊,並關連訊息
[[NSNotificationCenter defaultCenter]
addObserver:self selector:@selector(update) name:@"update" object:nil]
3. 在要發出通知訊息的地方
[[NSNotificationCenter defaultCenter]
postNotificationName:@"update" object:nil];
具體如何使用 Notifications
http://blog.sina.com.cn/s/blog_5df7dcaf0100c0q2.html
////////////////////////////////////////
第十四章: 使用 Notifications
使用者可能使用RaiseMan並開啟了幾個document, 然後他發現紫色的背景顏色實在是不利於閱讀文檔本文.
於是,他開啟Preferences panel修改背景顏色,不過令人失望的是,已經存在的文檔的背景顏色不會跟著改變.
於是,這個使用者可能會寫信給你告訴你這些. 你也許會回複:"defualts會在document建立的時候才讀取,
儲存document在開啟"實際上,使用者想說明的是他希望程式能立馬重新整理已經開啟的文檔. 如果這樣,那該怎麼做呢?
我們需要把所有開啟的document用一個list記錄起來麼?
--- 什麼是Notification? ---
這個要求其實也很容易實現. 每個運行中的application都有一個NSNotificationCenter的成員變數,
它的功能就類似公用欄. 對象註冊關注某個確定的notification(如果有人撿到一隻小狗,就去告訴我).
我們把這些註冊對象叫做 observer. 其它的一些對象會給center發送notifications(我撿到了一隻小狗).
center將該notifications轉寄給所有註冊對該notification感興趣的對象. 我們把這些發送notification的對象叫做 poster
很多的標準Cocoa類會發送notifications: 在改變size的時候,Window會發送notification;
選擇table view中的一行時,table view會發送notification;我們可以在線上協助文檔中查看到標準cocoa對象發送的notification
在我們的例子中,我們將MyDocumet對象註冊為observer. 而preference controller在使用者改變color時將發送notification.
MyDocument在接受到該notification後改變background color
在MyDocument對象釋放前,我們必須從notification center移除我們註冊的observer. 一般我們在dealloc方法中做這件事
-- Notifications 不是什麼 --
當程式員們聽到notification center的時候, 他們可能會聯想到IPC(進程間通訊).他們認為:
"我在一個程式中建立一個observer,然後在另外一個程式中發送一個notification". 這個設計沒有辦法工作的,
notification center允許同一個程式中的不同對象通許,它不能跨越不同的程式 [Notification 就是設計模 式中的 觀察者模式,
cocoa為我們實現了該模式, 就像Java也有同樣的實現一樣]
-- NSNotification 和 NSNotificationCenter
Notification對象非常簡單. 它就是poster要提供給observer的資訊包裹. notification對象有兩個重要的成員變數:
name 和 object. 一般object都是指向poster(為了讓observer在接受到notification時可以回調到poster)
所以,notification有兩個方法
- (NSString *)name
- (id)object
NSNotificaitonCernter是架構的大腦了.它允許我們註冊observer對象, 發送notification, 撤銷observer對象註冊
下面是它的一些常用方法
+ (NSNotificationCenter *)defaultCenter
返回notification center [類方法,返回全域對象, 單件模式.cocoa的很多的全域對象都是通過類似方法實現]
- (void)addObserver:(id)anObserver
selector:(SEL)aSelector
name:(NSString *)notificationName
object:(id)anObject
註冊anObserver對象:接受名字為notificationName, 寄件者為anObject的notification. 當anObject發送名字
為notificationName的notification時, 將會調用anObserver的aSelector方法,參數為該notification 14.1
. 如果notificationName為nil. 那麼notification center將anObject發送的所有notification轉寄給observer
. 如果anObject為nil.那麼notification center將所有名字為notificationName的notification轉寄給observer
- (void)postNotification:(NSNotification *)notification
發送notification至notification center 14.2
- (void)postNotificationName:(NSString *)aName
object:(id)anObject
建立並發送一個notification
- (void)removeObserver:(id)observer
移除observer
-- 發送一個Notification --
發送notification是其中最簡單的步驟了,所以我們從它開始實現.當我們接收到changeBackgroundColor:訊息時,
PreferenceController對象發送一個notification.
我們將notification命名為@"BNRColorChanged" ,我們使用一個全域常量來指定.(有經驗的程式員會使用一個首碼,
這樣避免和其他組件定義的notification混淆)開啟PreferenceController.h 添加下面的的外部申明
extern NSString * const BNRColorChangedNotification;
在PreferenceController.m中定義常量
NSString * const BNRColorChangedNotification = @"BNRColorChanged";
在PreferenceController.m修改changeBackgroundColor:方法
- (IBAction)changeBackgroundColor:(id)sender
{
NSColor *color = [colorWell color];
NSData *colorAsData =
[NSKeyedArchiver archivedDataWithRootObject:color];
[[NSUserDefaults standardUserDefaults] setObject:colorAsData
forKey:BNRTableBgColorKey];
NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
NSLog(@"Sending notification");
[nc postNotificationName:BNRColorChangedNotification object:self];
}
-- 註冊成為Observer --
要註冊一個observer, 我們必須提供幾個要數: 要成為observer的對象;所感興趣的notification的名字;
當notification發送時要調用的方法. 我們也可以指定要關注莫個對象的notification.(比如說,我們需要
關注莫個特定的window的resize的notification)
編輯MyDocument類的init方法
- (id)init
{
if (![super init])
return nil;
employees = [[NSMutableArray alloc] init];
NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
[nc addObserver:self
selector:@selector(handleColorChange:)
name:BNRColorChangedNotification
object:nil];
NSLog(@"Registered with notification center");
return self;
}
同時在dealloc方法,將MyDocument從notification center中移除
- (void)dealloc
{
[self setEmployees:nil];
NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
[nc removeObserver:self];
[super dealloc];
}
-- 處理Notification --
當一個notification發生時, handleColorChange:方法將被調用. 目前我們在方法中簡單的列印一些log.
- (void)handleColorChange:(NSNotification *)note
{
NSLog(@"Received notification: %@", note);
}
編譯運行程式,看到了我們想要的log了吧
-- userInfo Dictionary --
notification對象的object變數是poster,如果我們想要notification對象傳遞更多的資訊,
我們可以使用user info dictionary. 每個notification對象有一個變數叫 userInfo, 它是一個NSDictionary對象,
用來存放使用者希望隨著notification一起傳遞到observer的其它資訊. MyDocument將使用它來得到要改變的color.
在PreferenceController.m添加userInfo
- (IBAction)changeBackgroundColor:(id)sender
{
NSColor *color = [sender color];
NSData *colorAsData;
colorAsData = [NSKeyedArchiver archivedDataWithRootObject:color];
[[NSUserDefaults standardUserDefaults] setObject:colorAsData
forKey:BNRTableBgColorKey];
NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
NSLog(@"Sending notification");
NSDictionary *d = [NSDictionary dictionaryWithObject:color
forKey:@"color"];
[nc postNotificationName:BNRColorChangedNotification
object:self
userInfo:d];
}
在MyDocument.m,從userInfo中讀取到color
- (void)handleColorChange:(NSNotification *)note
{
NSLog(@"Received notification: %@", note);
NSColor *color = [[note userInfo] objectForKey:@"color"];
[tableView setBackgroundColor:color];
}
開啟幾個視窗,並改變背景顏色,現在,那些開啟的視窗的背景顏色立馬就變了.
-- 思考 --
通常當你將自己的一個對象設定為cocoa某個標準對象的delegate的時候,你同時或許也對該標準對象的notification感興趣.
例如,我們實現一個window的delegate來處理 windowShouldClose: , 我們也許會對 NSWindowDidResizeNotification
這樣的notification感興趣.
如果一個cocoa標準對象有一個delegate,同時它也發送notification的話, cocoa對象會自動將它的delegate對象註冊
成為observer來接受接受自己的notification. 如果我們實現了一個delegate,那麼delegate[也就是我們的對象]
要怎樣聲明來接受notification呢?[方法的名字是什麼?]
方法名字其實很簡單: 以notification名字為基準, 先將NS首碼去掉,接著將第一個字母改為小寫. 在將後面的Notification去掉,
然後加個冒號:. 例如,為了能接受到window的NSWindowDidResizeNotification, delegate可以實現方法:
- (void)windowDidResize:(NSNotification *)aNotification
當window改變大小時,這個方法將自動調用. 對於NSWindow,我們可以在.h或是協助文檔中找到類似的notification
來實現notification方法.
-- 挑戰 --
當程式不再是active狀態是,讓程式發出beep. 當unactive時,NSApplication會發送
NSApplicationDidResignActiveNotification的notificaiton. 而我們的AppController是NSApplication的delegate.
函數NSBeep()可以用來發出beep聲音