首先我們了解一下kvo和kvc的名次解釋
KVO的全稱是Key-Value Observing,俗稱“鍵值監(jiān)聽”,可以用于監(jiān)聽某個對象屬性值的改變
這里給出幾道kvo經(jīng)典的面試題
iOS用什么方式實(shí)現(xiàn)對一個對象的KVO?(KVO的本質(zhì)是什么?)
如何手動觸發(fā)KVO?
直接修改成員變量會觸發(fā)KVO么?
KVC的賦值和取值過程是怎樣的?原理是什么?
通過KVC修改屬性會觸發(fā)KVO么?
在接下來講解的過程中會一一解答
//這里給出了我們kvo最基本的使用方法
self.person1 = [[CCPerson alloc] init];
self.person1.age = 1;
// 給person1對象添加KVO監(jiān)聽
NSKeyValueObservingOptions options = NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld;
[self.person1 addObserver:self forKeyPath:@"age" options:options context:@"123"];
// 當(dāng)監(jiān)聽對象的屬性值發(fā)生改變時,就會調(diào)用
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context
{
NSLog(@"監(jiān)聽到%@的%@屬性值改變了 - %@ - %@", object, keyPath, change, context);
}
通過runtimeAPI我們可以知道使用了KVO監(jiān)聽的對象isa指針會指向另一個類NSKVONotifying_CCPerson,同時這個類的內(nèi)部會調(diào)用幾個方法。

image
從圖中我們不難發(fā)現(xiàn)
1.Person對象利用RuntimeAPI動態(tài)生成一個子類,并且讓instance對象的isa指向這個全新的子類
2.當(dāng)修改instance對象的屬性時,會調(diào)用Foundation的_NSSetXXXValueAndNotify函數(shù)
3.willChangeValueForKey:
4.父類原來的setter
5.didChangeValueForKey:
6.內(nèi)部會觸發(fā)監(jiān)聽器(Oberser)的監(jiān)聽方法( observeValueForKeyPath:ofObject:change:context:)
查看_NSSet*AndNotify的存在

image
_NSSet*ValueAndNotify的內(nèi)部實(shí)現(xiàn)

image
調(diào)用willChangeValueForKey:
調(diào)用原來的setter實(shí)現(xiàn)
調(diào)用didChangeValueForKey:
didChangeValueForKey:內(nèi)部會調(diào)用observer的observeValueForKeyPath:ofObject:change:context:方法
KVC的全稱是Key-Value Coding,俗稱“鍵值編碼”,可以通過一個key來訪問某個屬性
常見的API有
- (void)setValue:(id)value forKeyPath:(NSString *)keyPath;
- (void)setValue:(id)value forKey:(NSString *)key;
- (id)valueForKeyPath:(NSString *)keyPath;
- (id)valueForKey:(NSString *)key;
setValue:forKey:的原理

image
Value:forKey:的原理

image