🌰 :动画
首先建立一个YJCPerson类,该类有三个属性,分别是name,age和一个YJCDog,YJCDog有一个dogName属性atom
@interface YJCPerson : NSObject + (instancetype)personWithName:(NSString *)name age:(NSInteger)age dogName:(NSString *)dogName; - (instancetype)initWithName:(NSString *)name age:(NSInteger)age dogName:(NSString *)dogName; @end #import "YJCPerson.h" #import "YJCDog.h" @interface YJCPerson () @property (nonatomic, copy) NSString *name; @property (nonatomic, assign) NSInteger age; @property (nonatomic, strong) YJCDog *dog; @end @implementation YJCPerson + (instancetype)personWithName:(NSString *)name age:(NSInteger)age dogName:(NSString *)dogName{ YJCPerson *person = [[self alloc]initWithName:name age:age dogName:dogName];return person; } - (instancetype)initWithName:(NSString *)name age:(NSInteger)age dogName:(NSString *)dogName{ if (self = [self init]) { self.name = name; self.age = age; self.dog.dogName = dogName; } return self; } - (instancetype)init{ if (self = [super init]) { self.dog = [YJCDog new]; } return self; } @end
对于一个类,最好有便利构造方式spa
在VC中对该类添加监看指针
#import "ViewController.h" #import "YJCPerson.h" @interface ViewController () @property (nonatomic, strong) YJCPerson *person; @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; [self.person addObserver:self forKeyPath:@"name" options:NSKeyValueObservingOptionOld|NSKeyValueObservingOptionNew context:nil]; [self.person addObserver:self forKeyPath:@"dog.dogName" options:NSKeyValueObservingOptionOld|NSKeyValueObservingOptionNew context:nil]; [self.person setValue:@"YJC" forKey:@"name"];//KVC的setValue:forKey: [self.person setValue:@"大黄" forKeyPath:@"dog.dogName"];//KVC的setValue:forKeyPath:
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context
{
if ([keyPath isEqualToString:@"name"])
{
NSLog(@"YJCPerson 更名了,%@-->%@",[change valueForKey:@"old"],[change valueForKey:@"new"]);
}
else if ([keyPath isEqualToString:@"dog.dogName"])
{
NSLog(@"YJCPerson.dog 更名了,%@-->%@",[change valueForKey:@"old"],[change valueForKey:@"new"]);
}
}
- (YJCPerson *)person
{
return _person?:({
_person = [[YJCPerson alloc]init];
[_person setValue:@"name" forKey:@"name"];
[_person setValue:@"dog" forKeyPath:@"dog.dogName"];
_person;
});
}
//若是添加了KVO,必定要记得释放
- (void)dealloc
{
[self removeObserver:self.person forKeyPath:@"name"];
[self removeObserver:self.person forKeyPath:@"dog.dogName"];
}
@end
KVC主要是经过键值路径得到相应的属性,而且能够得到私有属性code
那么它获取路径的顺序是什么呢server
- (NSString *)getName;对象
- (NSString *)name;blog
- (NSString *)isName;rem
首先会依次查找这三个方法,固然既然声明的是属性,那么系统就默认实现了getter方法,因此会在第一步就找到.get
那么若是这三个方法都没有找到呢
由于name是string类型的,不不太明显.若是是array类型的话,系统会继续找响应的方法
例如-(id)objectInNameAtIndex:(NSUInteger)index;
若是依然没有找到,那么系统就会找- (id)valueForUndefineKey:(NSString *)key;若是该方法内依然没有找到相关key,则会crash,因此咱们能够经过从新该方法来防止程序crash
现实中KVC主要作的工做是对一些系统类的私有属性的赋值,像设置占位字符颜色啦,动画的一些属性啦什么的
KVO
KVO呢用法就是经过对某一实例的相关属性添加监看,系统会执行回调,切记添加了KVO必定要记得释放,写法呢大概就这个样子,示例而已
KVO的实现呢主要是该机制为被监控对象建立了一个分类NSKVONotifying_Class Class就是被监看的实例所属类.而后该机制会重写该属性的setter方法,setter在调用原setter方法以前和以后,经过KVO机制通知全部监看对象
固然这些行为是隐藏的,系统会经过runtime建立该分类,并把被监看对象的isa指针指向该分类,既然isa指针指向了该分类,那么setter方法天然就是调用该分类里已经重写过的setter方法咯,重写的时候添加了willChange和didChange两个方法用来通知监看对象
还有一点:遵循KVO赋值的方式才会触发KVO,直接对实例变量赋值是不会触发KVO机制的
切记,添加了监看必定要移除监看