iOS KVO

KVONSNotificationCenter都是iOS觀察者模式的一種實現。區別在於,相對於被觀察者和觀察者之間的關係,KVO是一對一的,而NSNotificationCenter是一對多的。KVO對被監聽對象無侵入性,不須要修改其內部代碼便可實現監聽。git

  1. KVO底層實現 KVO是基於runtime機制實現的,運用了一個isa-swizzling技術。isa-swizzling就是類型混合指針機制, 將2個對象的isa指針互相調換, 就是俗稱的黑魔法
  • 當某個類的屬性對象第一次被觀察時,系統就會在運行期動態地建立該類的一個派生類,在這個派生類中重寫基類中任何被觀察屬性的setter方法。派生類在被重寫的setter方法內實現真正的通知機制
  • 若是原類爲Person,那麼生成的派生類名爲NSKVONotifying_Person,每一個類對象中都有一個isa指針指向當前類,當一個類對象第一次被觀察,那麼系統會偷偷將isa指針指向動態生成的派生類,從而在給被監控屬性賦值時執行的是派生類的setter方法
  • 鍵值觀察通知依賴於NSObject的兩個方法:willChangeValueForKey:didChangevlueForKey:;在一個被觀察屬性發生改變以前,willChangeValueForKey:必定會被調用,這就會記錄舊的值。而當改變發生後,didChangeValueForKey:會被調用,繼而observeValueForKey:ofObject:change:context:也會被調用
  • 補充:KVO的這套實現機制中蘋果還偷偷重寫了class方法,讓咱們誤認爲仍是使用的當前類,從而達到隱藏生成的派生類
  1. 如何手動觸發KVO 手動調用willChangeValueForKey:didChangeValueForKey: 示例代碼以下:
一、自動
//默認返回YES
+ (BOOL)automaticallyNotifiesObserversForKey:(NSString *)key{
    if ([key isEqualToString:@"age"]) {
        return NO;//不觀察age屬性值得變化
    }
    return YES;
}

二、手動
- (void)setName:(NSString *)name{
    [self willChangeValueForKey:@"name"];
    _name = name;
    [self didChangeValueForKey:@"name"];
}
複製代碼
  1. 直接修改爲員變量會觸發KVO嗎 不會觸發KVO,添加KVOPerson實例,實際上是NSKVONotyfing_Person類在調用setter方法,不是調用Personsetter方法,而是NSKVONotyfing_Personsetter方法,由於修改爲員變量不是setter方法賦值
  2. 若是在項目中對Person類進行了監聽,也建立了一個NSKVONotifying_Person類,那麼會編譯經過麼 編譯經過,由於KVO是運行時刻建立的,並不在編譯時刻,在編譯時刻只有一個NSKVONotifying_Person,因此不報錯,能夠經過,可是此時KVO起不了做用

附:個人博客地址github

相關文章
相關標籤/搜索