IOS中的KVO機制詳解

ios開發有多種設計模式,其中有一種就叫作觀察者模式,即Key Value Observing(簡稱KVO)ios

KVO是Object -C中原聲支持的一種機制.設計模式


C、KVO 實現原理
當對一個對象添加觀察者,被觀察對象的屬性值發生變化時,觀察者會獲得通知,並對變化作出相應的處理。
D、KVO 的特性
1. 支持多個觀察者觀察同一屬性,也支持一個觀察者監聽不一樣屬性。
2. 利用它能夠很容易地實現視圖和數據模型的分離,當數據模型的屬性值改變以後,做爲監聽器的視圖就會被激發,並回調監聽器自身的監聽方法。
3. 對於KVC的基本的方法都定義在 NSKeyValueCoding 的非正式協議中,而且NSObject默認實現了該協議。相對的,在ObjC中要實現KVO則必須實現NSKeyValueObServing 協議,不過 NSObject 已經實現了該協議,所以幾乎全部的ObjC對象均可以使用KVO。
E、KVO在 ObjC 中的用法
1. 註冊觀察者:
- (void)addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(nullable void *)context;
2. 實現回調監聽方法:
- (void)observeValueForKeyPath:(nullable NSString *)keyPath ofObject:(nullable id)object change:(nullable NSDictionary<NSString*, id> *)change context:(nullable void *)context;
3. 移除觀察者:
- (void)removeObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath;
F、蘋果官方對於KVO的解釋及本人翻譯
Key-Value Observing Implementation Details
翻譯: KVO 實現詳解
Automatic key-value observing is implemented using a technique called isa-swizzling.
翻譯: KVO 是經過使用 isa-swizzling 技術實現的。
The isa pointer, as the name suggests, points to the object's class which maintains a dispatch table. This dispatch table essentially contains pointers to the methods the class implements, among other data.
翻譯: 這個 isa 指針,顧名思義,指向該對象的類,這個類包含了一個派遣信息表。這個派遣信息表本質上包含不少指針,這些指針指向了該類實現的全部方法。
When an observer is registered for an attribute of an object the isa pointer of the observed object is modified, pointing to an intermediate class rather than at the true class. As a result the value of the isa pointer does not necessarily reflect the actual class of the instance.
翻譯: 當一個對象的屬性被註冊了觀察者時,指向被觀察對象的 isa 指針就被修改了,修改成指向了一箇中間類而不是原來的類。其結果是,該 isa 指針不必定反映的就是該實例(被觀察者對象)的真實類。
You should never rely on the isa pointer to determine class membership. Instead, you should use the class method to determine the class of an object instance.
翻譯: 你永遠都不要依賴 isa 指針去肯定類成員,你應該使用類方法來肯定類的實例對象。
G、KVO 的底層實現:
1. KVO 的底層實現是經過Objective-C強大的運行時(runtime)實現的。
2. 當你第一次觀察一個對象object時,runtime 會動態地建立一個繼承自該對象object所屬類的子類,類名格式爲爲NSKVONotifying_[subclass名],同時保存註冊觀察者方法中的全部參數,包括監聽者、路徑、枚舉、攜帶參數等。
3. 這個新建立的子類重寫了全部被觀察屬性的 setter 方法,而且在內部給觀察者發送通知,通知全部觀察對象值的更改。
4. 最後把這個對象object的 isa 指針 ( isa 指針告訴 Runtime 系統這個對象的類是什麼類型的 ) 指向這個新建立的子類,此時這個被觀察的對象 object 就神奇地變成了新的子類的實例。

H、Demo驗證:
@interface People : NSObject
@property (nonatomic,strong) NSString *name;
@end
#import "ViewController.h"
#import "People.h"
@interface ViewController ()
@property (nonatomic,strong) People *p;
@end
@implementation ViewController
- (void)viewDidLoad {  
    [super viewDidLoad];    
    People *person = [[People alloc] init];    
    person.name = @"花完好";    
    self.p = person;    
        // 添加觀察者
    [person addObserver:self forKeyPath:@"name" options:NSKeyValueObservingOptionOld | NSKeyValueObservingOptionNew context:nil];    
    person.name = @"小魚兒";
}
// 實現監聽方法
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context{    
    NSLog(@"%@",change);
}
// 移除監聽者
-(void)dealloc{    
    [self.p removeObserver:self forKeyPath:@"name"];
}
@endatom

相關文章
相關標籤/搜索