[摘要]本文是對KVO-理解與簡單使用的講解,對學習IOS蘋果軟件開發有所幫助,與大家分享。
KVO
就是key value observing (鍵值監聽 /觀察者模式)/是一種回調機制
觀察者模式 :
一個目標對象管理所有依賴於他的觀察者對象 /並在它自身的狀態改變時主動通知觀察者對象 /這個制動通知通常是通過調用各觀察者對象所提供的接口方法來實現的 /觀察者模式比較完美的將目標對象和觀察者對象解耦
簡單來說 :
在某個對象注冊監聽者後/在被監聽的對象發生改變時/對象會發送一個通知給監聽者/以便監聽者執行回調
就是每次指定的被觀察的對象的屬性被修改後 /KVO就會自動通知響應的觀察者
KVO和KVC一樣都依賴於Runtime的動態及時 /都屬於鍵值編程而且底層實現機制都是isa-swizzling
KVO運用 : 例-監聽scrollView的contentOffset屬性/來完成用戶滾動時動態改變某些控件的屬性實現效果(包括漸變導航欄/下拉刷新控件等效果)
KVO使用 : 要求-對象必須能支持KVC機制(NSobject的子類都支持)/(也就是說 賦值通過setter或者KVC)
方法-注冊 指定被觀察者的屬性 /實現回調方法 /移除觀察
適用-很適用模型屬性被修改後 / 引發 UIView的變化 /當更改屬性的值後 /監聽對象會立刻得到通知
當需要檢測其他類的屬性值變化 /但又不想被觀察的類知道
有點像FBI監視嫌疑人 /這個時候就可以使用KVO
蘋果文檔對KVO的實現描述 :
Automatic key-value observing is implemented using a technique called isa-swizzling... 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 ..
也就是說/他使用的技術是ISA調和技術(isa-swizzling) /在我們對某個對象完成監聽注冊後/編譯器會修改所觀察到的對象的ISA指針 /可能還會修改了被監聽對象的某些屬性 /指向一個中間類而不是真正的類 /從某個意義來看 /這是一場騙局
系統實現KVO的步驟:
當類A的對象第一次被觀察的時候,系統會在運行期動態創建類A的派生類。我們稱為B(NSKVONotifying_A)。
在派生類B(NSKVONotifying_A)中重寫類A的setter方法,B類在被重寫的setter方法中實現通知機制。
在這個過程中, 被觀察對象的isa指針從指向原來A類的, 被KVO機制修改為指向B(NSKVONotifying_A)類, 來實現當前類屬性值改變的監聽
類B(NSKVONotifying_A)重寫會 class方法,將自己偽裝成類A。類B還會重寫dealloc方法釋放資源。
系統將所有指向類A對象的isa指針指向類B的對象。
KVC同KVO一樣 /通過isa-swizzling技術實現 /當觀察者被注冊為 一個對象的屬性 的觀察對象 的isa指針被修改(就是當觀察者被注冊為觀察對象 誰的觀察對象? 一個對象的屬性的觀察對象 然後 這個屬性的ISA指針被修改) /指向一個中間類 /而不是真是的類 /其結果是 isa指針的值並不一定能反應實例的實際類 /所以不能依靠isa指針來確定對象是否是一個類的成員 /應該使用class方法來確定對象實例的類
ISA指針 :
是一個指向Class類指針 /(專業術語是指向元類pointer to the metaclass 用來指向類的類型) /我們可以通過object_getClass方法來獲取這個值 /正常來說 class方法內部的實現就是獲取這個ISA指針代表的元類(metaclass) /但是在kvo機制中 /蘋果注冊監聽對象後 通過object_allocateClassPair動態重新創建了一個新類和元類 /此時object_getClass()獲取的就不是原來ISA指向的元類 /而是新建的元類
ISA指針的作用 :每個對象都有ISA指針 指向該對象的類 /他告訴Runtime系統這個對象的類是什麼 /所以對象注冊為觀察者時 /isa指針指向新類 /那麼這個被觀察者的對象就神奇的變成新子類的對象(或實例)了 /因而在該對象上對setting的調用就會調用已重寫的setter /從而激活鍵值通知機制
重寫setter方法 :
新類重寫了setter方法解析 :KVO的鍵值觀察通知依賴於NSObject的兩個方法willChangeValueForKey /didChangeValueForKey
被觀察屬性發生變化之前willChangeValueForKey被調用 /通知系統keyPath的屬性值即將改變
發生改變後didChangeValueForKey被調用 /通知系統keyPath的屬性值已經改變
之後- addObserver: forKeyPath: options: context 也會被調用
且重寫觀察屬性的setter方法這種繼承方式的注入是在運行時而不是編譯時實現的
KVO實現步驟
(options通常傳- NSkeyValueObservingOptionNew|NSkeyValueObservingOptonOld)
option是KVO裡常見的參數
NSkeyValueObservingOption枚舉:
NSkeyValueObservingOptionNew:提供更改前的值
NSkeyValueObservingOptionOld:提供更改後的值
NSkeyValueObservingOptionInitial:觀察最初的值(在注冊觀察服務的時候會調用一次觸發方法)
NSkeyValueObservingOptionPrior:分別在值修改前後觸發方法(即一次修改兩次觸發 )
注冊
(哪個要注冊KVO機制 / 觀察的屬性值 / 給你觀察鍵值變化的選擇 /方便傳輸你需要的數據 )
- addObserver: forKeyPath: options: context
實現(回調)
(觀察的屬性值/object??? / 存儲了一些變化的數據 比如變化前的數據 變化後的數據 如果注冊時context不為空 這裡就能收到)
- observeValueForKeyPath: ofObject: change: context:
移除
增加觀察與取消觀察是成對出現的 所以需要在最後的時候 移除觀察者(可以在- dealloc方法了寫)
- removeObserver: forKeyPath: