IOS 開發(fā)中的KVC 和KVO,實(shí)踐。
KVO
即key-value-observing,利用一個(gè)key來找到某個(gè)屬性并監(jiān)聽其值得改變。其實(shí)這也是一種典型的觀察者模式。
1,添加觀察者
2,在觀察者中實(shí)現(xiàn)監(jiān)聽方法,observeValueForKeyPath: ofObject: change: context:
3,移除觀察者
interface WebviewViewController ()
@property (nonatomic, strong) WKWebView *webView;
@property (nonatomic, strong) UIProgressView *progressView;
@end
// 讓對(duì)象 self 監(jiān)聽對(duì)象 self.webView 的estimatedProgress屬性
// options屬性可以選擇是哪個(gè) /* NSKeyValueObservingOptionNew =0x01, 新值 NSKeyValueObservingOptionOld =0x02, 舊值 */
// context 帶參數(shù)(字典等)
[self.webView addObserver:self
?? ? ? ? ? ? ? ? ? forKeyPath:@"estimatedProgress"
? ? ? ? ? ? ? ? ? ? ? options:NSKeyValueObservingOptionNew
? ? ? ? ? ? ? ? ? ? ? context:nil];
#pragma mark- KVO監(jiān)聽
/*
* 當(dāng)對(duì)象的屬性發(fā)生改變會(huì)調(diào)用該方法
*@param keyPath 監(jiān)聽的屬性
* @param object 監(jiān)聽的對(duì)象
* @param change 新值和舊值
* @param context 額外的數(shù)據(jù)
*/
- (void)observeValueForKeyPath:(NSString*)keyPath
? ? ? ? ? ? ? ? ? ? ? ofObject:(id)object
? ? ? ? ? ? ? ? ? ? ? ? change:(NSDictionary *)change
?? ? ? ? ? ? ? ? ? ? ? context:(void*)context
{
? ? if ([keyPath isEqualToString:@"estimatedProgress"]) {
? ? ? ? self.progressView.progress = self.webView.estimatedProgress;
? ? ? ? // 加載完成
? ? ? ? if(self.webView.estimatedProgress? >=1.0f) {
? ? ? ? ? ? [UIView animateWithDuration:0.25f animations:^{
? ? ? ? ? ? ? ? self.progressView.alpha=0.0f;
? ? ? ? ? ? ? ? self.progressView.progress=0.0f;
? ? ? ? ? ? }];
? ? ? ? }else{
? ? ? ? ? ? self.progressView.alpha=1.0f;
? ? ? ? }
? ? }
}
- (void)dealloc {
? ? [self.webView removeObserver:self forKeyPath:@"estimatedProgress" context:nil];
}
KVO是利用runtime動(dòng)態(tài)添加了子類,當(dāng)一個(gè)類的屬性被觀察的時(shí)候,系統(tǒng)會(huì)通過runtime動(dòng)態(tài)的創(chuàng)建一個(gè)該類的派生類,并且會(huì)在這個(gè)類中重寫基類被觀察的屬性的setter方法,而且系統(tǒng)將這個(gè)類的isa指針指向了派生類,從而實(shí)現(xiàn)了給監(jiān)聽的屬性賦值時(shí)調(diào)用的是派生類的setter方法。重寫的setter方法會(huì)在調(diào)用原setter方法前后,通知觀察對(duì)象值得改變。
調(diào)用willChangeValueForKey:和didChangevlueForKey:,最后調(diào)用observeValueForKey:ofObject:change:context:方法,是通過上兩個(gè)方法來記錄新值和舊值的。