1. 程式人生 > >【轉載】iPhone開發之NSNotificationCenter(通知)的使用方法

【轉載】iPhone開發之NSNotificationCenter(通知)的使用方法

iPhone軟體開發的時候會遇到這種情況:開啟APP後會在後臺執行某個方法,例如下載檔案,下載完成後可能需要呼叫某個方法來重新整理介面,這時候可能沒法在下載的函式中回撥。NSNotificationCenter(通知)是一個很好的選擇。

通知使用起來灰常的簡單:

1、定義通知:

[[NSNotificationCenter defaultCenter] addObserver: self         selector: @selector(callBack)             name: @"back"            object: nil];

2、定義通知中使用的方法:

- (void)callBack{  NSLog(@"i am back."); }

3、呼叫通知:

- (void)getIT{  NSLog(@"get it.");  //發出通知  [[NSNotificationCenter defaultCenter] postNotificationName:@"back" object:self]; }

在呼叫通知的時候程式會在整個專案中尋找此通知的名稱,找到後發出請求,因此通知的名稱需要在整個專案中唯一。

  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聲音

// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.

- (void)viewDidLoad

{

    [super viewDidLoad];

    self.view.backgroundColor = [UIColor colorWithRed:0.05 green:0.6 blue:0.3 alpha:1.0];

    self.navigationController.navigationBar.tintColor = [UIColor colorWithRed:0.2 green:0.3 blue:0.5 alpha:1];

    count = 0;

    timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(updateTimer:) userInfo:nil repeats:YES];

    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(receiveNotification:) name:@"Note" object:nil];

}

-(void)updateTimer:(NSTimer*)time{

    count++;

    self.title = [NSString stringWithFormat:@"%d",count];

    if (count%5 == 0) {

        [[NSNotificationCenter defaultCenter] postNotificationName:@"Note" object:nil];

    }

}

-(void)receiveNotification:(NSNotification*)note{

    UIAlertView* noteView = [[UIAlertView alloc] initWithTitle:nil message:@"You receive a notification!!" delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil];

    [noteView show];

    [noteView release];

}

- (void)viewDidUnload

{

    [[NSNotificationCenter defaultCenter] removeObject:self];

    [super viewDidUnload];

    // Release any retained subviews of the main view.

    // e.g. self.myOutlet = nil;

    if (timer != nil) {

        [timer release];

        timer = nil;

    }

}

以下內容轉自http://blog.sina.com.cn/s/blog_793cad6e0100sa6x.html

什麼是Notification?

這個要求其實也很容易實現. 每個執行中的application都有一個NSNotificationCenter的成員變數,它的功能就類似公共欄. 物件註冊關注某個確定的notification(如果有人撿到一隻小狗,就去告訴我). 我們把這些註冊物件叫做 observer. 其它的一些物件會給center傳送notifications(我撿到了一隻小狗). center將該notifications轉發給所有註冊對該notification感興趣的物件. 我們把這些傳送notification的物件叫做poster

很多的標準Cocoa類會發送notifications: 在改變size的時候,Window會發送notification; 選擇table view中的一行時,table view會發送notification;我們可以在線上幫助文件中檢視到標準cocoa物件傳送的notification

在物件釋放前,我們必須從notification center移除我們註冊的observer. 一般我們在dealloc方法中做這件事

NSNotification類

提供給observer的資訊包裹. notification物件有兩個重要的成員變數: name 和 object.

- (NSString *)name;

- (id)object;

- (NSDictionary *)userInfo;我們想要notification物件傳遞更多的資訊

+ (id)notificationWithName:(NSString *)aName object:(id)anObject;

+ (id)notificationWithName:(NSString *)aName object:(id)anObject userInfo:(NSDictionary*)aUserInfo;

NSNotificationCenter類

+ (id)defaultCenter;返回notification center [類方法,返回全域性物件, 單件模式.cocoa的很多的全域性物件都是通過類似方法實現]

- (void)addObserver:(id)observer selector:(SEL)aSelector name:(NSString *)aName object:(id)anObject;

 如果notificationName為nil. 那麼notification center將anObject傳送的所有notification轉發給observer

. 如果anObject為nil.那麼notification center將所有名字為notificationName的notification轉發給observer

- (void)postNotification:(NSNotification *)notification;

- (void)postNotificationName:(NSString *)aName object:(id)anObject;

- (void)postNotificationName:(NSString *)aName object:(id)anObject userInfo:(NSDictionary*)aUserInfo;

- (void)removeObserver:(id)observer;

- (void)removeObserver:(id)observer name:(NSString *)aName object:(id)anObject;