轻量级KVO ——》 KVO 管理 observeValueForKeyPath
在這篇文章中,我會實現一個自己用的簡單KVO類,我認為KVO非常棒,然而對于我大部分的使用場景來說,有這兩個問題:
1. 我不喜歡在observeValueForKeyPath:ofObject:change:context:方法里通過keyPath值來做調度,當Observe比較多的對象時,會使得代碼變得雜亂和迷惑。 2. 必須手動的來注冊和刪除一個觀察者,如果能自動做就好了。
So,我們開始這個實現。這個技巧我第一次是在THObserversAndBinders項目中見到,本篇內容也僅僅描述了一下里面的做法,同時做了簡化。
首先,我們定義一下我們的這個類,我們這個幫助類的類名是Observer:
@interface Observer : NSObject + (instancetype)observerWithObject:(id)objectkeyPath:(NSString*)keyPathtarget:(id)targetselector:(SEL)selector; @endObserver類的這個類方法有四個參數,每個參數都是自解釋的,我選擇使用target/action模式,當然也可以使用block,但是那樣的話需要做weakSelf/strongSelf的轉換,你懂的,通常來說分來來做比較好。
我們做的是在初始化方法中設置KVO,并在dealloc方法中移除。這意味著一旦Observer對象被retain,我們就有了一個觀察者,下面這段代碼是從我的一個ViewCOntroller中拿來的:
self.usernameObserver = [Observer observerWithObject:self.userkeyPath:@"name"target:selfselector:@selector(usernameChanged)];把這個Observer對象作為一個屬性放在ViewController中來保證被retain,一旦我們的Viewcontroller被釋放,就會設置它為nil,observer就停止觀察了。
在這個實現中,使用一個weak引用指向被觀察對象和觀察者(target)是很重要的,如果兩個中的其中一個是nil,我們就停止向觀察者發送消息。
@interface Observer () @property (nonatomic, weak) id target; @property (nonatomic) SEL selector; @property (nonatomic, weak) id observedObject; @property (nonatomic, copy) NSString* keyPath; @end初始化器里設置KVO通知,使用self作為context,如果我們會有一個子類也添加類似的觀察者時就很有必要了。
- (id)initWithObject:(id)object keyPath:(NSString*)keyPath target:(id)target selector:(SEL)selector {if (self) {self.target = target;self.selector = selector;self.observedObject = object;self.keyPath = keyPath;[object addObserver:self forKeyPath:keyPath options:0 context:self];}return self; }一旦被觀察者發生變化,我們就通知觀察者(target),如果它還存在的話:
- (void)observeValueForKeyPath:(NSString*)keyPath ofObject:(id)object change:(NSDictionary*)change context:(void*)context { if (context == self) {id strongTarget = self.target;if ([strongTarget respondsToSelector:self.selector]) { #pragma clang diagnostic push #pragma clang diagnostic ignored "-Warc-performSelector-leaks"[strongTarget performSelector:self.selector]; #pragma clang diagnostic pop} } }最后在dealloc方法中移除觀察者對象:
- (void)dealloc {id strongObservedObject = self.observedObject;if (strongObservedObject) {[strongObservedObject removeObserver:self forKeyPath:self.keyPath];} }這就是全部內容了。還有很多可以擴展的地方,比如增加block的支持,或者我比較喜歡的trick:再增加愛一個方便的構造方法用來第一次直接調用action。然而,我想的是展現出這個技術的核心部分,你可以根據自己的需求來調整它。
這個技術的優點是在使用KVO的時候不需要記住太多東西,僅僅retain住Observer對象,然后在完成的試試置為nil即可,剩下的會自動完成。
原文作者是Chris Eidhof,objc.io的創辦者
原文地址:Lightweight Key-Value Observing
總結
以上是生活随笔為你收集整理的轻量级KVO ——》 KVO 管理 observeValueForKeyPath的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: mac 键盘按键符号讲解
- 下一篇: iOS 关于枚举的使用