KVO

? ? ? ? ? KVO在OC中是實現鍵值(key-value-observing)觀察的方式,在設計模式中是典型的觀察者模式, 當觀察者將被觀察者的某個屬性設置為觀察的對象時,若被觀察的該屬性值發生變化時,就會觸發觀察者對象所實現的KVO接口方法,從而達到通知觀察者的目的。

? ? ? ? 簡單來說KVO可以通過監聽key,來獲得value的變化,用來在對象之間監聽狀態變化。KVO的定義都是對NSObject的擴展來實現的,Objective-C中有個顯式的NSKeyValueObserving類別名,所以對于所有繼承了NSObject的類型,都能使用KVO。

? ? ? ? ?KVO的實現是基于iOS runtime機制的isa-swizzling(指針替換),當一個對象的屬性被注冊成被觀察對象時,會生成一個中間類繼承自該類,然后將該類的isa指針指向新生成的子類,這樣被觀察的對象就變成了這個中間類,同時重寫了被觀察屬性的setter方法,當新對象的屬性發生變化時,則會依次通知注冊的觀察者對象。

自動KVO(默認方式)

a、添加觀測者

-(void)addObserver:(NSObject*)observer forKeyPath:(NSString*)keyPath options:(NSKeyValueObservingOptions)options context:(nullablevoid*)context;

b、當觀測的屬性值發生改變時調用的函數

-(void)observeValueForKeyPath:(nullable NSString*)keyPath ofObject:(nullable id)object change:(nullable NSDictionary<NSKeyValueChangeKey,id>*)change context:(nullablevoid*)context;

c、移除觀察者

- (void)removeObserver:(NSObject*)observer forKeyPath:(NSString*)keyPath context:(nullablevoid*)context;

? ? ? ? 注意,如果被觀察的屬性沒有調用Setter方法,而是通過直接訪問其實例變量(_下劃線方法)是不會觸發回調的。

手動KVO

? ? ? ? KVO在屬性發生改變的時候默認是自動調用的,如果需要手動的控制這個調用時機,那么在被觀察的對象.m文件中調用如下方法:

+(BOOL)automaticallyNotifiesObserversForKey:(NSString*)key{

returnYES;//默認,自動模式

returnNO;//手動模式

}

同時在屬性變化之前,調用:

-(void)willChangeValueForKey:(NSString*)key;

在屬性變化之后,調用:

-(void)didChangeValueForKey:(NSString*)key;

? ? ? ? 其實無論屬性的值是否發生改變,是否調用Setter方法,只要調用了willChangeValueForKey:和didChangeValueForKey:就會觸發回調。

依賴鍵KVO

如果在當前Person類中引入另外一個Dog類:

@interface Dog : NSObject

@property (copy, nonatomic) NSString *age;

@property (copy, nonatomic) NSString *name;

@end

那么此時我們怎么通過Person來觀察Dog類的age屬性呢?

[_p addObserver:self forKeyPath:@"dog.age" options:NSKeyValueObservingOptionNew ? ?context:nil];

我們現在希望,只要Dog類中有屬性的變化,就會通知到Person類,如果我們每一個屬性都添加一遍觀察者會很麻煩,這里就需要用到屬性依賴。我們在Person類的.m中添加一個方法:

+(NSSet<NSString *> *)keyPathsForValuesAffectingValueForKey:(NSString *)key

{

? ? NSSet *keyPath = [super keyPathsForValuesAffectingValueForKey:key];

? ? if([keyisEqual:@"dog"]) {

? ? ? ? keyPath = [[NSSetalloc]initWithObjects:@"_dog.age",@"_dog.name",nil];

? ? }

? ? returnkeyPath;

}

同時在添加觀察者時,不用對dog具體的屬性添加,直接對dog進行觀察。

[_p addObserver:self forKeyPath:@"dog" options:NSKeyValueObservingOptionNew context:nil];

? ? ? ? 設置鍵之間的依賴關系+(NSSet<NSString*>*)keyPathsForValuesAffectingValueForKey:(NSString*)key;當添加一個被觀察的keyPath,這個方法就會走。其大概意思是就是:用一組鍵的值去影響另一個鍵值。注意該方法一定要考慮非指定key時的情況要調用[super keyPathsForValuesAffectingValueForKey:key],不能影響其他的情況。

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容