测试代码:
测试结果:
代码如下:
#import <Foundation/Foundation.h>
typedef void(^kvoBlock)(id oldValue,id newValue);
@interface NSObject (KVO)
/**
<#Description#>
@param observer 被观察对象
@param keyPath 被观察的属性
@param block 属性值改变触发的操作
*/
-(void)addObserver:(NSObject *)observer
forKeyPath:(NSString *)keyPath
kvoBlock:(kvoBlock)block;
@end
#import "NSObject+KVO.h"
#import <objc/runtime.h>
typedef void(^deallocBlock)(void);
@interface KVOController: NSObject
@property (nonatomic,strong) NSObject *observeredObj;
@property (nonatomic,strong) NSMutableArray<deallocBlock> *blockArr;
@end
@implementation KVOController
-(NSMutableArray<deallocBlock> *)blockArr{
if (!_blockArr) {
_blockArr = @[].mutableCopy;
}
return _blockArr;
}
-(void)dealloc{
NSLog(@"KVOController dealloc");
[self.blockArr enumerateObjectsUsingBlock:^(deallocBlock _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
obj();
}];
}
@end
// 根据观察者,被观察者,keyPath拼成唯一的字典的key
#define KEYPATH(a, b, c) [NSString stringWithFormat:@"%@-%@-%@",[a class], [b class], c]
@interface NSObject ()
@property (nonatomic,strong) NSMutableDictionary<NSString *,kvoBlock> *dict;
@property (nonatomic,strong) KVOController *kvoController;
@end
@implementation NSObject (KVO)
-(void)addObserver:(NSObject *)observer
forKeyPath:(NSString *)keyPath
kvoBlock:(kvoBlock)block{
self.dict[KEYPATH(self, observer, keyPath)] = block;
self.kvoController.observeredObj = observer;
__unsafe_unretained typeof(self) weakSelf = self;
[self.kvoController.blockArr addObject:^{
[observer removeObserver:weakSelf forKeyPath:keyPath];
}];
// NSLog(@"observer = %@",observer);
// NSLog(@"self = %@",self);
[observer addObserver:self
forKeyPath:keyPath
options:NSKeyValueObservingOptionOld | NSKeyValueObservingOptionNew
context:NULL];
}
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context{
kvoBlock block = self.dict[KEYPATH(self, object, keyPath)];
if (block) {
block([change valueForKey:NSKeyValueChangeOldKey], [change valueForKey:NSKeyValueChangeNewKey]);
}
}
-(NSMutableDictionary<NSString *,kvoBlock> *)dict{
NSMutableDictionary *tmpDic = objc_getAssociatedObject(self, @selector(dict));
if (!tmpDic) {
tmpDic = @{}.mutableCopy;
objc_setAssociatedObject(self, @selector(dict), tmpDic, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
return tmpDic;
}
-(KVOController *)kvoController{
KVOController *kvoController = objc_getAssociatedObject(self, @selector(kvoController));
if (!kvoController) {
kvoController = [KVOController new];
objc_setAssociatedObject(self, @selector(kvoController), kvoController, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
return kvoController;
}
@end