深入剖析通知中心和KVO 要先瞭解KVO和通知中心,就得先說說觀察者模式,那麼觀察者模式到底是什麼呢?下麵來詳細介紹什麼是觀察者模式。 觀察者模式 A對B的變化感興趣,就註冊成為B的觀察者,當B發生變化時通知A,告知B發生了變化,這就是觀察者模式。 觀察者模式定義了一對一對多的依賴關係,讓多個觀察者 ...
深入剖析通知中心和KVO
要先瞭解KVO和通知中心,就得先說說觀察者模式,那麼觀察者模式到底是什麼呢?下麵來詳細介紹什麼是觀察者模式。
觀察者模式
-A對B的變化感興趣,就註冊成為B的觀察者,當B發生變化時通知A,告知B發生了變化,這就是觀察者模式。 觀察者模式定義了一對一對多的依賴關係,讓多個觀察者對象同時監聽某一個主題對象,這個主題對象在狀態發生變化時,會通知所有的觀察者對象,使他們能夠自動更新自己或者作出相應的一些動作。 在開發中,我們可能會接觸到觀察者模式的實現方式,有NSNotificationCenter、KVO等。
下麵就來上正菜了,在下麵我會給大家詳細講解通知中心和KVO到底是什麼,對於這兩個,我也是模模糊糊,搞不清到底是什麼東西,所以才找了資料,來整理整理,順便寫篇博客分享給大家。
通知中心
- 通知中心就是以NSNotificationCenter為中心,觀察者往Center中註冊對某個主題對象的變化感興趣,主體對象通過NSNotificationCenter進行變化廣播,所有的變化和監聽行為都向同一個中心進行註冊,所有對象的變化也通過同一個中心對外廣播。
通知中心的執行順序
通過NSNotificationCenter的addObserver:selector:name:object介面來註冊通知中心
被觀察的對象,通過postNotificationName:object:userInfo:向通知中心發送某一類型通知。
當有通知來的時候,Center會調用觀察者註冊的介面來廣播通知,同時傳遞存儲著更改內容的NSNotification對象。
當該通知不再使用時,可以在dealloc方法里removeObserver:刪除觀察者
代碼
main.m
//
// main.m
// 通知中心
//
// Created by ma c on 16/5/16.
// Copyright © 2016年 Jujue. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "Observer.h"
#import "HttpClient.h"
int main(int argc, const char * argv[]) {
@autoreleasepool {
// insert code here...
//1、通知中心註冊通知對象
//2、需要給通知中心發送消息的地方post通知
//3、執行註冊通知時設置的方法
Observer *observer = [[Observer alloc]init];
//在通知中心註冊成為Observer的觀察者
[observer registNotification];
HttpClient *client = [[HttpClient alloc]init];
//發送消息
[client postNotifi];
}
return 0;
}
Observer.m
//
// Observer.m
// 通知中心
//
// Created by ma c on 16/5/16.
// Copyright © 2016年 Jujue. All rights reserved.
//
#import "Observer.h"
@implementation Observer
- (void)registNotification
{
NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
//註冊成為觀察者 觀察對象是Observer
[notificationCenter addObserver:self selector:@selector(doAction:) name:@"Observer" object:nil];
}
- (void)doAction:(NSNotification *)notifi
{
//發送者是哪個類就輸出的是什麼東西-這個例子列印出來是 <HttpClient: 0x10020ead0>
NSLog(@"%@",notifi.object);
//列印結果 name = xiaoyu;
NSLog(@"%@",notifi.userInfo);
}
- (void)dealloc
{
[[NSNotificationCenter defaultCenter]removeObserver:self];
}
@end
HttpClient.m
//
// HttpClient.m
// 通知中心
//
// Created by ma c on 16/5/16.
// Copyright © 2016年 Jujue. All rights reserved.
//
#import "HttpClient.h"
@implementation HttpClient
- (void)postNotifi
{
NSDictionary *info = @{@"name":@"xiaoyu"};
NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
[notificationCenter postNotificationName:@"Observer" object:self userInfo:info];
}
@end
KVO(鍵值觀察)
KVO是一個典型的觀察者模式,觀察者在鍵值改變時會得到通知。iOS中有個Notification的機制,也可以獲得通知,但這個機制需要有個Center,相比之下KVO更加簡潔而直接。
NSKeyValueObserving非正式協議定義了一種機制,它允許對象去監聽其它對象的某個屬性的修改。NSObject提供了一個NSKeyValueObserving協議的預設實現,它為所有對象提供了一種自動發送修改通知的能力。我們可以通過禁用自動發送通知並使用這個協議提供的方法來手動實現通知的發送,以便更精確地去處理通知。
KVO的實現步驟
(1)註冊需要觀察的對象的屬性addObserver:forKeyPath:options:context:
- (2)實現observeValueForKeyPath:ofObject:change:context:方法,這個方法當觀察的屬性變化時會自動調用.在這個方法中還通過NSKeyValueObservingOptionNew這個參數要求把新值在dictionary中傳遞過來。
(3)取消註冊觀察removeObserver:forKeyPath:context:
手動設置KVO
//關閉某key值的KVO + (BOOL)automaticallyNotifiesObserversForKey:(NSString *)key { BOOL automatic = YES; if ([key isEqualToString:@"age"]) { automatic = NO; } else { automatic = [super automaticallyNotifiesObserversForKey:key]; } return automatic; } //重寫setter方法手動設置KVO - (void)setAge:(int)age { //手動設置KVO if (_age != age) { [self willChangeValueForKey:@"age"]; _age = age; [self didChangeValueForKey:@"age"]; } }
註意:一般的建議是,在獲取屬性值時,可以用實例變數,在設置屬性值時,儘量用setter方法,以保證屬性的KVO特性。
KVO的實現原理
- 當某一個類的實例第一次使用KVO的時候,系統就會在運行期間動態的創建該類的一個派生類,該類的命名規則一般是以NSKVONotifying為首碼,以原本的類名為尾碼。並且將原型的對象的isa指針指向該派生類。同時在派生類中重載了使用KVO的屬性的setter方法,在重載的setter方法中實現真正的通知機制,正如前面我們手動實現KVO一樣。這麼做是基於設置屬性會調用 setter 方法,而通過重寫就獲得了 KVO 需要的通知機制。當然前提是要通過遵循 KVO 的屬性設置方式來變更屬性值,如果僅是直接修改屬性對應的成員變數,是無法實現 KVO 的。
代碼-大家可以去我的github去下載