? ? ? ?原生KVO的實現依賴于強大的runtime運行時機制,實現原理大致為:當觀察某對象A的屬性時,會動態的創建這個類的子類,并為這個新的子類重寫了Setter方法,在這個Setter方法里面負責通知觀察者屬性變化的情況。
? ? ? ?前段時間面試的時候,面試官問我,如果不用系統的KVO模式,自己來實現一種設計模式,當時可能由于緊張,一下子沒反應過來,最后結果可想而知,現在想來,對比現在所在的外包公司的種種不公平待遇,總結下來一句話,肚子里沒貨還真不行。
? ? ? 閑話不多扯,先來簡單說一下如何自己實現NSNotificationCenter通知模式,然后,細聊如何通過協議實現KVO,不同于原生KVO的實現方案。
? ? ? 通知中心實現方案,首先進行角色劃分,一個單例類A+抽象協議接口(包含接收到通知后實現的接口和發出通知的接口)Protocol+具體的實現類B;
? ? ? ??客戶端: ? ?A ? 包含屬性數組 ?,B遵循Protocol,實現協議方法,A數組持有B對象,當A發出通知時,取出數組中的B對象,通過運行時,讓B實現協議方法,從而達到通知的目的。
這里,我們重點看一下KVO的實現方案,首先進行角色劃分:
第一步 : 抽象出接口:所有觀察者必須遵循這個協議
// 抽象觀察者Observer
@protocol Observer
- (void)update:(Observable *)o msg:(NSObject *)msg;
@end
第二步:定義一個基類Observable,所有被觀察者對象都必須繼承于Observable基類
// 注冊觀察者- (void)addObserver:(id)o; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
// 刪除觀察者- (void)deleteObserver:(id)o;// 刪除所有觀察者
- (void)deleteObservers;// 觀察者數量
- (NSInteger)countObserver;// 通知
- (void)notifyObservers;- (void)notifyObservers:(NSObject *)msg;
// 更新數據
- (void)setChanged;// 取消更新
- (void)clearChanged;// 獲取更新狀態
- (BOOL)hasChanged;
Observable.m文件實現:
#import "Observable.h"@interface Observable()
@property (nonatomic,strong) NSMutableArray *obsArray;
@property (nonatomic,assign) BOOL changed;
@end
// 被觀察者
@implementation Observable
- (instancetype)init{?
? ? ? ?if (self = [super init]) {? ?
? ? ?_obsArray = [NSMutableArray array];? ? ? ?
?_changed = NO;? ? }?
? return self;}
// 注冊觀察者
- (void)addObserver:(id)o {? ? [_obsArray addObject:o];}
// 刪除觀察者
- (void)deleteObserver:(id)o {? ? [_obsArray removeObject:o];}
// 刪除所有觀察者
- (void)deleteObservers {? ? [_obsArray removeAllObjects];}
// 觀察者數量
- (NSInteger)countObserver?{? ? return _obsArray.count;}
- (void)notifyObservers {? ? [self notifyObservers:nil];}
- (void)notifyObservers:(NSObject *)msg
{? ?
? ? if (!_changed)?{? ? ? ? return ;? ? }? ?
? ? [self clearChanged];? ?
? ? ?for (idobj in _obsArray) {
[obj update:self msg:msg];
}
}
// 更新數據
- (void)setChanged {
_changed = YES;
}
// 取消更新
- (void)clearChanged {
_changed = NO;
}
// 獲取更新狀態
- (BOOL)hasChanged {
return _changed;
}
客戶端實現:
WXObservable *observable = [WXObservable new];
[observable addObserver:[CoffeeObserver new]];
[observable addObserver:[SimpleObserver new]];
[observable setTitle:@"思維的切換"];
[observable push];
[observable push];
[observable push];