iOS 設計模式-NSNotificationCenter 通知中心

通知介紹

每個應用程序都有一個通知中心(NSNotificationCenter)實例,專門負責協助不一樣對象之間的消息通訊
任何一個對象均可以向通知中心發佈通知(NSNotification),描述本身在作什麼。
其餘感興趣的對象(Observer)能夠申請在某個特定通知發佈時(或在某個特定的對象發佈通知時)收到這個通知

初始化通知中心

        // 初始化通知中心
        NSNotificationCenter *center =[NSNotificationCenter defaultCenter];

註冊通知監聽器

通知中心(NSNotificationCenter)提供了方法來註冊一個監聽通知的監聽器(Observer)async

方法一:post

- (void)addObserver:(id)observer selector:(SEL)aSelector name:(NSString *)aName object:(id)anObject;
  • observer:監聽器,即誰要接收這個通知
  • aSelector:收到通知後,回調監聽器的這個方法,而且把通知對象當作參數傳入
  • aName:通知的名稱。若是爲nil,那麼不管通知的名稱是什麼,監聽器都能收到這個通知
  • anObject:通知發佈者。若是爲anObject和aName都爲nil,監聽器都收到全部的通知

方法二:動畫

- (id)addObserverForName:(NSString *)name object:(id)obj queue:(NSOperationQueue *)queue 
               usingBlock:(void (^)(NSNotification *note))block;
  • name:通知的名稱
  • obj:通知發佈者
  • block:收到對應的通知時,會回調這個block
  • queue:決定了block在哪一個操做隊列中執行,若是傳nil,默認在當前操做隊列中同步執行

發佈通知

通知中心(NSNotificationCenter)提供了相應的方法來幫助發佈通知atom

- (void)postNotification:(NSNotification *)notification;
發佈一個notification通知,可在notification對象中設置通知的名稱、通知發佈者、額外信息等
 
- (void)postNotificationName:(NSString *)aName object:(id)anObject;
發佈一個名稱爲aName的通知,anObject爲這個通知的發佈者
 
- (void)postNotificationName:(NSString *)aName object:(id)anObject userInfo:(NSDictionary *)aUserInfo;
發佈一個名稱爲aName的通知,anObject爲這個通知的發佈者,aUserInfo爲額外信息

取消註冊通知監聽器

通知中心不會保留(retain)監聽器對象,在通知中心註冊過的對象,必須在該對象釋放前取消註冊。不然,當相應的通知再次出現時,通知中心仍然會向該監聽器發送消息。由於相應的監聽器對象已經被釋放了,因此可能會致使應用崩潰
•通知中心提供了相應的方法來取消註冊監聽器
- (void)removeObserver:(id)observer;
- (void)removeObserver:(id)observer name:(NSString *)aName object:(id)anObject;
通常在監聽器銷燬以前取消註冊(如在監聽器中加入下列代碼):
- (void)dealloc {
  //[super dealloc];  非ARC中須要調用此句
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}

實例代碼

兩個新聞機構(騰訊新聞、新浪新聞),每當發佈新聞時,通知訂閱了該新聞的用戶。spa

新聞機構類 NewsCompany.h線程

//  新聞發佈機構

#import <Foundation/Foundation.h>

@interface NewsCompany : NSObject
/**
 *  機構名稱
 */
@property (nonatomic, copy) NSString *name;
@end

NewsCompany.m3d

#import "NewsCompany.h"

@implementation NewsCompany

@end

訂閱者類code

Person.hserver

#import <Foundation/Foundation.h>

@interface Person : NSObject
/**
 * 姓名
 */
@property (nonatomic, copy) NSString *name;

- (void)newsCome:(NSNotification *)note;
@end

Person.m對象

#import "Person.h"
#import "NewsCompany.h"

@implementation Person

// 收到通知後,回調監聽器的這個方法,而且把通知對象當作參數傳入
- (void)newsCome:(NSNotification *)note
{
    // 通知的發佈者
    NewsCompany *obj = note.object;
    
    NSLog(@"%@接收到了%@發出的通知,通知內容是:%@", self.name, obj.name, note.userInfo);
}

// 通常在監聽器銷燬以前取消註冊
- (void)dealloc
{
//    [super dealloc];
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}
@end

通知中心

main.m

#import <Foundation/Foundation.h>
#import "Person.h"
#import "NewsCompany.h"

int main(int argc, const char * argv[])
{
    @autoreleasepool {
        // 1.初始化機構
        NewsCompany *tx = [[NewsCompany alloc] init];
        tx.name = @"騰訊新聞";
        
        NewsCompany *sina = [[NewsCompany alloc] init];
        sina.name = @"新浪新聞";
        
        // 2.初始化2我的
        Person *zhangsan = [[Person alloc] init];
        zhangsan.name = @"張三";
        
        Person *lisi = [[Person alloc] init];
        lisi.name = @"李四";
        
        // 初始化通知中心
        NSNotificationCenter *center =[NSNotificationCenter defaultCenter];
        
        // 3.註冊通知監聽器
        // zhangsan只監聽tx發出的junshi_news_come通知
        [center addObserver:zhangsan selector:@selector(newsCome:) name:@"junshi_news_come" object:nil];
        // lisi監聽tx發的全部通知
        [center addObserver:lisi selector:@selector(newsCome:) name:nil object:tx];
        
        // 4.發佈通知
        // tx發佈了一則叫作junshi_news_come的通知
        [center postNotificationName:@"junshi_news_come"
                              object:tx
                            userInfo:@{@"title" : @"伊拉克戰爭中止了",
                                       @"intro" : @"伊拉克戰爭中止了.........."}];
        
        // sina發佈了一則叫作junshi_news_come的通知
        [center postNotificationName:@"yule_news_come"
                              object:sina
                            userInfo:@{@"title" : @"6456456456456",
                                       @"intro" : @"7657567567567"}];
        
    }
    return 0;
}

運行結果:

其它通知

UIDevice設備通知

UIDevice類提供了一個單粒對象,它表明着設備,經過它能夠得到一些設備相關的信息,好比電池電量值(batteryLevel)、電池狀態(batteryState)、設備的類型(model,好比iPod、iPhone等)、設備的系統(systemVersion)
經過[UIDevice currentDevice]能夠獲取這個單粒對象
UIDevice對象會不間斷地發佈一些通知,下列是UIDevice對象所發佈通知的名稱常量:
  • UIDeviceOrientationDidChangeNotification // 設備旋轉
  • UIDeviceBatteryStateDidChangeNotification // 電池狀態改變
  • UIDeviceBatteryLevelDidChangeNotification // 電池電量改變
  • UIDeviceProximityStateDidChangeNotification // 近距離傳感器(好比設備貼近了使用者的臉部)

鍵盤通知

系統發出鍵盤通知時,會附帶一下跟鍵盤有關的額外信息(字典),字典常見的key以下:
  • UIKeyboardFrameBeginUserInfoKey // 鍵盤剛開始的frame
  • UIKeyboardFrameEndUserInfoKey // 鍵盤最終的frame(動畫執行完畢後)
  • UIKeyboardAnimationDurationUserInfoKey // 鍵盤動畫的時間
  • UIKeyboardAnimationCurveUserInfoKey // 鍵盤動畫的執行節奏(快慢)

使用方式

監聽:

    // 2.監聽鍵盤的通知
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillChangeFrame:) name:UIKeyboardWillChangeFrameNotification object:nil];

取消監聽:

- (void)dealloc
{
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}

最後 

在使用過程當中,咱們須要注意,最後通知的線程,是由發起通知的線程決定的。若是發起通知是主線程,則收到的通知也是主線程。

更新UI必需要在主線程中更新,所以,咱們最好在全部的通知回調中,都判斷一下,若是當前線程不是主線程,則回到主線程。

宏定義以下,這個在SDWebImage裏有這個宏定義。

#define dispatch_main_async_safe(block)\
    if ([NSThread isMainThread]) {\
        block();\
    } else {\
        dispatch_async(dispatch_get_main_queue(), block);\
    }
相關文章
相關標籤/搜索