NSObject+kvo.h
#import <Foundation/Foundation.h>
@interface NSObject (kvo)
- (void)hk_addObserver:(NSObject *_Nonnull)observer forKeyPath:(NSString *_Nullable)keyPath options:(NSKeyValueObservingOptions)options context:(nullable void *)context;
@end
NSObject+kvo.m
#import "NSObject+kvo.h"
#import <objc/message.h>//消息发送!!
/*
1.创建HANKKVO_Perosn子类
2.修改调用者的isa指针
3.重写set --> 添加!
*/
@implementation NSObject (kvo)
- (void)hk_addObserver:(NSObject *_Nonnull)observer forKeyPath:(NSString *_Nullable)keyPath options:(NSKeyValueObservingOptions)options context:(nullable void *)context
{
//1.动态生成一个类
NSString * oldName = NSStringFromClass([self class]);
NSString * newName = [@"HankKVO_" stringByAppendingString:oldName];
//继承谁,叫什么
Class MyClass = objc_allocateClassPair([self class], newName.UTF8String, 0);
//注册
objc_registerClassPair(MyClass);
//2.动态修改一个对象的类型!!
object_setClass(self, MyClass);
//3.添加setName方法
NSString *aSelectorName = [NSString stringWithFormat:@"set%@:",[keyPath capitalizedString]];
SEL selector = NSSelectorFromString(aSelectorName);
class_addMethod(MyClass, selector, (IMP)setProperty, "v@:@");
//将观察者保存到当前对象中!!
objc_setAssociatedObject(self, @"observer", observer, OBJC_ASSOCIATION_ASSIGN);
//将keyPath保存到当前对象中!!
objc_setAssociatedObject(self, @"keyPath", keyPath, OBJC_ASSOCIATION_ASSIGN);
}
//OC 的方法,每次调用,有两个隐式参数!!
void setProperty(id self,SEL _cmd,NSString * value){
//保存class
id class = [self class];
//拿出保存到在当前对象中的属性
NSString *keyPath = objc_getAssociatedObject(self, @"keyPath");
//改变类型 self -> super
object_setClass(self, class_getSuperclass([self class]));
//获取Set方法
NSString *aSelectorName = [NSString stringWithFormat:@"set%@:",[keyPath capitalizedString]];
SEL selector = NSSelectorFromString(aSelectorName);
//发送父类方法 [super setName:newName]
objc_msgSend(self, selector,value);
//改回子类 super -> self
object_setClass(self, class);
//拿出保存到在当前对象中的属性
id observer = objc_getAssociatedObject(self, @"observer");
//发送回调方法
objc_msgSend(observer, @selector(observeValueForKeyPath:ofObject:change:context:),keyPath,self,nil,nil);
}
@end
ViewController.m
#import "ViewController.h"
#import "Person.h"
#import "NSObject+kvo.h"
@interface ViewController ()
@property (nonatomic, strong) Person *p;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
Person * p = [[Person alloc] init];
[p hk_addObserver:self forKeyPath:@"age" options:NSKeyValueObservingOptionNew context:nil];
_p = p;
}
//通知!!
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context
{
NSLog(@"发现属性变化:%@",keyPath);
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
_p.age = @"18";
NSLog(@"现在的Age:%@",_p.age);
}