1.手动控制kvo的触发 + (BOOL)automaticallyNotifiesObserversForKey:(NSString *)key; 返回NO ; 然后在改变value前 调用[object willChangeValueForKey:@"key"];
在改变value后, 调用[object didChangeValueForKey:@"key"] ; 2.隔层kvo观察
@interface Dog : NSObject
@property(nonatomic)NSInteger age;
@property(nonatomic)NSInteger *level;
@end
#import <Foundation/Foundation.h>
#import "Dog.h"
@interface Person : NSObject
@property(nonatomic,strong)Dog *dog;
@end
#import "Person.h"
@implementation Person
-(instancetype)init{
self = [super init];
if (self) {
_dog = [[Dog alloc]init];
}
return self;
}
+(NSSet<NSString *> *)keyPathsForValuesAffectingValueForKey:(NSString *)key{
NSSet *keyPath = [super keyPathsForValuesAffectingValueForKey:key];
if ([key isEqualToString:@"dog"]) {
NSArray *arr = @[@"_dog.level",@"_dog.age"];
keyPath = [keyPath setByAddingObjectsFromArray:arr];
}
return keyPath;
}
@end
//设置观察
self.person = [[Person alloc] init];
[self.person addObserver:self forKeyPath:@"dog" options:NSKeyValueObservingOptionOld context:nil];
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context
{
NSLog(@"change:%@",change);
}
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
self.person.dog.age++;
}
2.KVO的底层实现
#import "NSObject+PRKVO.h"
#import <objc/runtime.h>
@implementation NSObject (PRKVO)
-(void)PR_addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(void *)context
{
//1.自定义一个NSKVONotifying_Person子类
NSString *oldClassName = NSStringFromClass(self.class);
NSString *newClassName = [@"PRKVO_" stringByAppendingString:oldClassName];
//创建一个类
Class MyClass = objc_allocateClassPair(self.class, newClassName.UTF8String, 0);
//注册该类
objc_registerProtocol(MyClass);
//2.动态修改
object_setClass(self, MyClass);
//3.添加setName方法,重新父类setName
class_addMethod(MyClass, @selector(setName:), (IMP)haha, "v@:@");
}
void haha(id self,SEL _cmd,NSString *newName){
NSLog(@"!%@",newName);
}