iOS設(shè)計模式 —— KV0

iOS設(shè)計模式 —— KV0

刨根問底KVO

KVO 全稱 Key-Value Observing。中文叫鍵值觀察。KVO其實是一種觀察者模式,觀察者在鍵值改變時會得到通知,利用它可以很容易實現(xiàn)視圖組件和數(shù)據(jù)模型的分離,當(dāng)數(shù)據(jù)模型的屬性值改變之后作為監(jiān)聽器的視圖組件就會被激發(fā),激發(fā)時就會回調(diào)監(jiān)聽器自身。相比Notification,KVO更加的簡單直接。

KVO的操作方法由NSKeyValueCoding提供,而他是NSObject的類別,也就是說ObjC中幾乎所有的對象都支持KVO操作。

KVO的使用也很簡單,就是簡單的3步。

注冊需要觀察的對象的屬性addObserver:forKeyPath:options:context:

實現(xiàn)observeValueForKeyPath:ofObject:change:context:方法,這個方法當(dāng)觀察的屬性變化時會自動調(diào)用.在這個方法中還通過NSKeyValueObservingOptionNew這個參數(shù)要求把新值在dictionary中傳遞過來。

取消注冊觀察removeObserver:forKeyPath:context:

我們觀察下代碼實現(xiàn),探究實現(xiàn)原理:

Person.h

1

2

3

4

5

6

7

8

9

#import

@interfacePerson:NSObject

- (void)registerObserver;

@property(nonatomic,assign)NSIntegerage;

@end

Person.m

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

#import"Person.h"

@implementationPerson

- (void)registerObserver {

[selfaddObserver:selfforKeyPath:@"age"options:NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOldcontext:nil];

}

- (NSString*)description {

return[NSStringstringWithFormat:@"%@,%ld",[selfvalueForKey:@"isa"],self.age];

}

- (void)observeValueForKeyPath:(NSString*)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void*)context {

if([keyPath isEqualToString:@"age"]) {

NSLog(@"%@",change);

}else{

[superobserveValueForKeyPath:keyPath ofObject:object change:change context:context];

}

}

- (void)dealloc {

[selfremoveObserver:selfforKeyPath:@"age"];

}

main函數(shù)

1

2

3

4

5

6

7

8

Person *p =[[Person alloc] init];

p.age =20;

NSLog(@"%@",p);

[p registerObserver];

p.age =30;

NSLog(@"%@",p);

運行程序打印出的log日志為:

1

2

3

4

5

6

7

Person,20

{

kind =1;

new =30;

old =20;

}

NSKVONotifying_Person,30

不要太驚訝,我們慢慢解釋。

我重寫的Person類的description方法,使用KVC拿到isa指針,獲取到self的類名,我們發(fā)現(xiàn)在使用KVO之前類名是Person,但注冊了KVO之后,類名變成了NSKVONotifying_Person。

主要是因為KVO的實現(xiàn)使用了isa-swizzling。在程序運行時Person會生成一個派生類NSKVONotifying_Person,在這個派生類中重寫基類中任何被觀察屬性的setter方法,用來欺騙系統(tǒng)頂替原先的類。在setter方法中實現(xiàn)真正的通知機制.

1

2

3

4

5

6

7

//可以到偽代碼

- (void)setAge:(int)age

{

[supersetAge:age];

[監(jiān)聽器observeValueForKeyPath:@"age"ofObject:selfchange:@{}context:nil];

}

我們又可以猜測,使用KVO,內(nèi)部一定執(zhí)行setter方法。

當(dāng)我們把上面代碼p.age = 30;改成p->_age = 30;

你會發(fā)現(xiàn)KVO的方法不走了,也證實了這點。

如果p不提供setAge,getAge方法,還想用KVO.

1

2

3

[pwillChangeValueForKey:@"age"];

p->_age =30;

[pdidChangeValueForKey:@"age"];

蘋果官方KVO文檔:

https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/KeyValueObserving/KeyValueObserving.html

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容