[object addObserver:observer forKeyPath:@"text" options:NSKeyValueObservingOptionNew context:nil];實現回調方法
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
if([keyPath isEqualToString:@"text"])
{
NSLog(@"text:@%@", change[NSKeyValueChangeNewKey]);
}
}
釋放的時候取消注冊
[object removeObserver:self forKeyPath:@"text"];
這裡有幾個問題
注冊的時候參數過多釋放的時候必須取消注冊只有一個回調,當注冊的觀察者過多的時候,會使得代碼變得雜亂下面我們將針對這幾個問題進行封裝
定義一個觀察者類@interface XYObserver : NSObject @end @interface XYObserver () @property (nonatomic, assign) XYObserverType type; // 觀察者的類型 @property (nonatomic, weak) id target; // 被觀察的對象的值改變時後的響應方法所在的對象 @property (nonatomic, assign) SEL selector; // 被觀察的對象的值改變時後的響應方法 @property (nonatomic, copy) XYObserver_block_sourceObject_new_old block; // 值改變時執行的block @property (nonatomic, assign) id sourceObject; // 被觀察的對象 @property (nonatomic, strong) NSString *keyPath; // 被觀察的對象的keyPath -(instancetype) initWithSourceObject:(id)sourceObject keyPath:(NSString*)keyPath target:(id)target selector:(SEL)selector type:(XYObserverType)type; -(instancetype) initWithSourceObject:(id)sourceObject keyPath:(NSString*)keyPath block:(XYObserver_block_sourceObject_new_old)block; @end添加NSObject關於觀察者的類別
@interface NSObject (XYObserver)
@property (nonatomic, readonly, strong) NSMutableDictionary *observers;
/**
* api parameters 說明
*
* sourceObject 被觀察的對象
* keyPath 被觀察的屬性keypath
* target 默認是self
* selector @selector(propertyNew:)
@selector(propertyNew:old:)
@selector(propertyIn:new:)
@selector(propertyIn:new:old:)
* type 根據selector自動賦值
* block selector, block二選一
*/
-(void) observeWithObject:(id)sourceObject property:(NSString*)property;
-(void) observeWithObject:(id)sourceObject property:(NSString*)property block:(XYObserver_block_sourceObject_new_old)block;
-(void) removeObserverWithObject:(id)sourceObject property:(NSString *)property;
-(void) removeObserverWithObject:(id)sourceObject;
-(void) removeAllObserver;
@end
在這裡我們查詢的實現的方法
-(void) observeWithObject:(id)object property:(NSString*)property{
SEL aSel = NSSelectorFromString([NSString stringWithFormat:@"%@New:", property]);
if ([self respondsToSelector:aSel]) {
[self observeWithObject:object
keyPath:property
target:self
selector:aSel
type:XYObserverType_new];
return;
}
.
.
.
}
用block的話就直接保存
-(void) observeWithObject:(id)object property:(NSString*)property block:(XYObserver_block_sourceObject_new_old)block{
[self observeWithObject:object keyPath:property block:block];
}
處理實現方法
-(void) observeValueForKeyPath:(NSString*)keyPath ofObject:(id)object change:(NSDictionary*)change context:(void*)context
{
__weak __typeof(self) weakSelf = self;
if (_block) {
_block(weakSelf, change[NSKeyValueChangeNewKey], change[NSKeyValueChangeOldKey]);
return;
}
if (_type == XYObserverType_new) {
action(_target, _selector, change[NSKeyValueChangeNewKey]);
}else if (_type == XYObserverType_new_old) {
action(_target, _selector, change[NSKeyValueChangeNewKey], change[NSKeyValueChangeOldKey]);
}else if (_type == XYObserverType_self_new) {
action(_target, _selector, self, change[NSKeyValueChangeNewKey]);
}else if (_type == XYObserverType_self_new_old) {
action(_target, _selector, self, change[NSKeyValueChangeNewKey], change[NSKeyValueChangeOldKey]);
}
}
把所有的觀察者添加到一個字典裡
-(void) observeWithObject:(id)object keyPath:(NSString*)keyPath target:(id)target selector:(SEL)selector type:(XYObserverType)type{
XYObserver *ob = [[XYObserver alloc] initWithSourceObject:object keyPath:keyPath target:target selector:selector type:type];
NSString *key = [NSString stringWithFormat:@"%@_%@", object, keyPath];
[self.observers setObject:ob forKey:key];
}
-(void) observeWithObject:(id)object property:(NSString*)property block:(XYObserver_block_sourceObject_new_old)block{
[self observeWithObject:object keyPath:property block:block];
}
-(id) observers{
id object = objc_getAssociatedObject(self, NSObject_observers);
if (nil == object) {
NSMutableDictionary *dic = [NSMutableDictionary dictionaryWithCapacity:8];
objc_setAssociatedObject(self, NSObject_observers, dic, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
return dic;
}
return object;
}
當對象釋放的時候會清空字典裡的觀察者對象,在觀察者對象的dealloc方法裡面取消注冊觀察者
-(void) dealloc
{
if (_sourceObject) { [_sourceObject removeObserver:self forKeyPath:_keyPath]; }
}
為了方便書寫,定義幾個宏
#define ON_KVO_1_( __property ) -(void) __property##New:(id)newValue #define ON_KVO_2_( __property ) -(void) __property##New:(id)newValue old:(id)oldValue #define ON_KVO_3_( __property ) -(void) __property##In:(id)sourceObject new:(id)newValue #define ON_KVO_4_( __property ) -(void) __property##In:(id)sourceObject new:(id)newValue old:(id)oldValue
[self observeWithObject:self property:@"testKVO"];
ON_KVO_4_(testKVO){
NSLogD(@"obj:%@ new:%@ old:%@", sourceObject, newValue, oldValue);
}
[self observeWithObject:self property:@"testKVO2" block:^(id sourceObject, id newValue, id oldValue) {
NSLogD(@"obj:%@ new:%@ old:%@", sourceObject, newValue, oldValue);
}];
這個封裝的優點是在使用KVO的時候不需要記住太多東西.
代碼可以在https://github.com/uxyheaven/XYQuickDevelop下載到