KVO-理解與簡單使用,KVO-理解簡單使用
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: