通知中心其實是在程序內部提供了消息廣播的一種機制,它容許咱們在低程度耦合的狀況下,知足控制器與一個任意的對象進行通訊的目的。每個 iOS 程序(即每個進程)都有一個本身的通知中心,即 NSNotificationCenter 對象,該對象採用單例設計模式,能夠經過類方法 defaultCenter 得到當前進程惟一的通知中心對象。一個 NSNotificationCenter 能夠有許多的通知消息 NSNotification,對於每個 NSNotification 能夠有不少的觀察者 Observer 來接收通知。NSNotificationCenter 是 iOS 中通知中心的靈魂,由該類實現了觀察者模式,並給開發者提供了諸如註冊、刪除觀察者的接口。設計模式
通知中心以同步的方法將消息轉發到全部的觀察者中,換言之 NSNotificationCenter 在發送消息後,會一直等待被調用的方法執行完畢,而後返回控制權到主函數中,再接着執行後面的功能,即這是一個同步阻塞的操做。若是咱們須要異步的處理消息,直接返回控制權,則應該使用通知隊列 NSNotificationQueue,在子線程中將通知加入到通知隊列中,在多線程程序中,通知會被分發到每個發送消息的線程中,這可能與觀察者註冊時所在的線程已經不是同一個線程。多線程
任何一個對象均可以向通知中心發佈通知(NSNotification),描述本身在作什麼。其餘感興趣的對象(Observer)能夠申請在某個特定通知發佈時(或在某個特定的對象發佈通知時)收到這個通知。異步
使用 [NSNotificationCenter defaultCenter] 發送的通知不管是在主線程仍是子線程中被註冊,觀察者註冊的選擇器方法都會在主線程中被執行。執行順序爲:main runloop -> 發送通知 -> 觀察者選 擇器方法(按照觀察者註冊的順序執行)-> 通知發送者方法中其它的操做 -> main runloop。async
在子線程中使用 [NSNotificationQueue defaultQueue] 將通知加入到通知隊列中,觀察者選擇器方法就會在子線程中被執行。子線程執行順序爲:發送通知 -> 觀察者選擇器方法(按照觀察者註冊的順序同 步執行)-> 通知發送者方法中其它的操做。ide
若是要在同一臺機器上進行進程間的通訊,須要使用 NSDistributedNOtificationCenter。函數
優點:oop
缺點:post
目的:動畫
方式:ui
通知和代理的區別:
通知中心是同步的,仍是異步的 ?
系統發送 Notification,用戶不須要手動發送通知,設置的事件觸發時,系統自動發送通知。
通知中心不會保留(retain)監聽器對象,在通知中心註冊過的對象,必須在該對象釋放前取消註冊。不然,當相應的通知再次出現時,通知中心仍然會向該監聽器發送消息。由於相應的監聽器對象已經被釋放了,因此可能會致使應用崩潰。通常在監聽器銷燬以前取消註冊(如在監聽器中加入下列代碼):
- (void)dealloc { // [super dealloc]; // 非 ARC 中須要調用此句 [[NSNotificationCenter defaultCenter] removeObserver:self]; }
在註冊、移除通知時,通知名稱標示(aName)使用系統定義的標示。
註冊通知(觀察者)
Objective-C
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(playFinished) name:AVPlayerItemDidPlayToEndTimeNotification object:nil];
Swift
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(ViewController.playFinished), name:AVPlayerItemDidPlayToEndTimeNotification, object: nil)
移除通知(觀察者)
Objective-C
[[NSNotificationCenter defaultCenter] removeObserver:self name:AVPlayerItemDidPlayToEndTimeNotification object:nil];
Swift
NSNotificationCenter.defaultCenter().removeObserver(self, name:AVPlayerItemDidPlayToEndTimeNotification, object:nil)
使用 [NSNotificationCenter defaultCenter] 發送的通知不管是在主線程仍是子線程中被註冊,觀察者註冊的選擇器方法都會在主線程中被執行。
執行順序:main runloop -> 發送通知 -> 觀察者選擇器方法(按照觀察者註冊的順序執行)-> 通知發送者方法中其它的操做 -> main runloop
通知(消息)的建立
+ (instancetype)notificationWithName:(NSString *)aName object:(nullable id)anObject; + (instancetype)notificationWithName:(NSString *)aName object:(nullable id)anObject userInfo:(nullable NSDictionary *)aUserInfo; public convenience init(name aName: String, object anObject: AnyObject?) public init(name: String, object: AnyObject?, userInfo: [NSObject : AnyObject]?) 參數說明: aName :通知名稱 anObject :傳遞給觀察者的任意對象,通知發佈者(是誰要發佈通知) aUserInfo:傳遞的消息內容,自定義字典,能夠傳遞更多附加信息,一些額外的信息(通知發佈者傳遞給通知接收者的信息內容)
Objective-C
// 不帶消息內容 NSNotification *notification1 = [NSNotification notificationWithName:@"notification1" object:self]; // 帶消息內容 NSNotification *notification2 = [NSNotification notificationWithName:@"notification2" object:self userInfo:@{@"name":_name, @"age":_age}];
Swift
// 不帶消息內容 let notification1 = NSNotification(name: "notification1", object: self) // 帶消息內容 let notification2 = NSNotification(name: "notification2", object: self, userInfo: ["name":name, "age":age])
發送通知
- (void)postNotification:(NSNotification *)notification; - (void)postNotificationName:(NSString *)aName object:(nullable id)anObject; - (void)postNotificationName:(NSString *)aName object:(nullable id)anObject userInfo:(nullable NSDictionary *)aUserInfo; public func postNotification(notification: NSNotification) public func postNotificationName(aName: String, object anObject: AnyObject?) public func postNotificationName(aName: String, object anObject: AnyObject?, userInfo aUserInfo: [NSObject : AnyObject]?) 參數說明: notification:發送的通知(消息) aName :通知名稱 anObject :傳遞給觀察者的任意對象,通知發佈者 aUserInfo :傳遞的消息內容,自定義字典,能夠傳遞更多附加信息
Objective-C
// 發送建立好的消息 [[NSNotificationCenter defaultCenter] postNotification:notification1]; // 直接發送消息,不帶消息內容 [[NSNotificationCenter defaultCenter] postNotificationName:@"notification3" object:self]; // 直接發送消息,帶消息內容 [[NSNotificationCenter defaultCenter] postNotificationName:@"notification4" object:self userInfo:@{@"name":_name, @"age":_age}];
Swift
// 發送建立好的消息 NSNotificationCenter.defaultCenter().postNotification(notification1) // 直接發送消息,不帶消息內容 NSNotificationCenter.defaultCenter().postNotificationName("notification3", object: self) // 直接發送消息,帶消息內容 NSNotificationCenter.defaultCenter().postNotificationName("notification4", object: self, userInfo: ["name":name, "age":age])
註冊通知(觀察者)
- (void)addObserver:(id)observer selector:(SEL)aSelector name:(nullable NSString *)aName object:(nullable id)anObject; public func addObserver(observer: AnyObject, selector aSelector: Selector, name aName: String?, object anObject: AnyObject?) 參數說明: observer :觀察者,即誰要接收這個通知; aSelector:收到通知後調用何種方法,即回調函數,而且把通知對象當作參數傳入; aName :通知的名字,也是通知的惟一標示,編譯器就經過這個找到通知的。 爲 nil 時,表示註冊全部通知,那麼不管通知的名稱是什麼,監聽器都能收到這個通知; anObject :通知發送者,爲 nil 時,表示監聽全部發送者的通知。若是 anObject 和 aName 都爲 nil,監聽器都收到全部的通知。 - (id)addObserverForName:(NSString *)name object:(id)obj queue:(NSOperationQueue *)queue usingBlock:(void (^)(NSNotification *note))block; 參數說明: name :通知的名稱 obj :通知發佈者 queue:決定了 block 在哪一個操做隊列中執行,若是傳 nil,默認在當前操做隊列中同步執行 block:收到對應的通知時,會回調這個 block
Objective-C
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(notification1Sel) name:@"notification1" object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(notification2Sel:) name:@"notification2" object:nil]; // 通知觸發方法,通知無內容 - (void)notification1Sel { } // 通知觸發方法,通知有內容 - (void)notification2Sel:(NSNotification *)notification { // 接收用戶消息內容 NSDictionary *userInfo = notification.userInfo; }
Swift
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(ViewController.notification1Sel), name: "notification1", object: nil) NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(ViewController.notification2Sel(_:)), name: "notification2", object: nil) // 通知觸發方法,通知無內容 func notification1Sel() { } // 通知觸發方法,通知有內容 func notification2Sel(notification:NSNotification) { // 接收用戶消息內容 let userInfo = notification.userInfo }
移除通知(觀察者)
- (void)removeObserver:(id)observer; - (void)removeObserver:(id)observer name:(nullable NSString *)aName object:(nullable id)anObject; public func removeObserver(observer: AnyObject) public func removeObserver(observer: AnyObject, name aName: String?, object anObject: AnyObject?) 參數說明: observer:觀察者,即在什麼地方接收通知; aName :通知的名字,也是通知的惟一標示,編譯器就經過這個找到通知的。 anObject:通知發送者,爲 nil 時,表示移除知足條件的全部發送者的通知。
Objective-C
// 移除此觀察者的全部通知 [[NSNotificationCenter defaultCenter] removeObserver:self]; // 移除指定名字的通知 [[NSNotificationCenter defaultCenter] removeObserver:self name:@"notification1" object:nil];
Swift
// 移除此觀察者的全部通知 NSNotificationCenter.defaultCenter().removeObserver(self) // 移除指定名字的通知 NSNotificationCenter.defaultCenter().removeObserver(self, name:"notification1", object:nil)
在子線程中使用 [NSNotificationQueue defaultQueue] 將通知加入到通知隊列中,觀察者選擇器方法就會在子線程中被執行。
| -> -> -> -> -> -> -> -> main runloop -> -> -> -> -> -> -> -> -> -> | 執行順序:main runloop -> | | -> main runloop | -> 發送通知 -> 觀察者選擇器方法(按照觀察者註冊的順序同步執行)-> 通知發送者方法中其它的操做 |
發送異步通知
- (void)enqueueNotification:(NSNotification *)notification postingStyle:(NSPostingStyle)postingStyle; - (void)enqueueNotification:(NSNotification *)notification postingStyle:(NSPostingStyle)postingStyle coalesceMask:(NSNotificationCoalescing)coalesceMask forModes:(nullable NSArray<NSString *> *)modes; 參數說明: notification:通知 postingStyle:發佈方式 coalesceMask:合併方式 modes :運行循環模式,nil 表示 NSDefaultRunLoopMode NSPostingStyle :發佈方式 NSPostWhenIdle = 1, :空閒時發佈 NSPostASAP = 2, :儘快發佈 NSPostNow = 3 :當即發佈 NSNotificationCoalescing :合併方式 NSNotificationNoCoalescing = 0, :不合並 NSNotificationCoalescingOnName = 1, :按名稱合併 NSNotificationCoalescingOnSender = 2 :按發佈者合併
Objective-C
// 建立通知 NSNotification *asyncNotification = [NSNotification notificationWithName:@"asyncNotification" object:self]; dispatch_async(dispatch_get_global_queue(0, 0), ^{ // 將通知添加到發送隊列中,發送通知 [[NSNotificationQueue defaultQueue] enqueueNotification:asyncNotification postingStyle:NSPostWhenIdle]; });
移除異步通知
- (void)dequeueNotificationsMatching:(NSNotification *)notification coalesceMask:(NSUInteger)coalesceMask; 參數說明: notification:通知 coalesceMask:合併方式
Objective-C
// 移除通知,不是當即發佈的通知能夠被移除 [[NSNotificationQueue defaultQueue] dequeueNotificationsMatching:asyncNotification coalesceMask:0];
UIDevice 類提供了一個單例對象,它表明着設備,經過它能夠得到一些設備相關的信息,好比電池電量值(batteryLevel)、電池狀態(batteryState)、設備的類型(model,好比 iPod、iPhone 等)、設備的系統(systemVersion)。經過 [UIDevice currentDevice] 能夠獲取這個單例對象。
UIDevice 對象會不間斷地發佈一些通知,下列是 UIDevice 對象所發佈通知的名稱常量:
UIDeviceOrientationDidChangeNotification // 設備旋轉 UIDeviceBatteryStateDidChangeNotification // 電池狀態改變 UIDeviceBatteryLevelDidChangeNotification // 電池電量改變 UIDeviceProximityStateDidChangeNotification // 近距離傳感器(好比設備貼近了使用者的臉部)
咱們常常須要在鍵盤彈出或者隱藏的時候作一些特定的操做,所以須要監聽鍵盤的狀態。
鍵盤狀態改變的時候,系統會發出一些特定的通知:
UIKeyboardWillShowNotification // 鍵盤即將顯示 UIKeyboardDidShowNotification // 鍵盤顯示完畢 UIKeyboardWillHideNotification // 鍵盤即將隱藏 UIKeyboardDidHideNotification // 鍵盤隱藏完畢 UIKeyboardWillChangeFrameNotification // 鍵盤的位置尺寸即將發生改變 UIKeyboardDidChangeFrameNotification // 鍵盤的位置尺寸改變完畢
系統發出鍵盤通知時,會附帶一下跟鍵盤有關的額外信息(字典),字典常見的 key 以下:
UIKeyboardFrameBeginUserInfoKey // 鍵盤剛開始的 frame UIKeyboardFrameEndUserInfoKey // 鍵盤最終的 frame(動畫執行完畢後) UIKeyboardAnimationDurationUserInfoKey // 鍵盤動畫的時間 UIKeyboardAnimationCurveUserInfoKey // 鍵盤動畫的執行節奏(快慢)