? :
首先创建一个YJCPerson类,该类有三个属性,分别是name,age和一个YJCDog,YJCDog有一个dogName属性
@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
对于一个类,最好有便利构造方式
在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:(NSDictionaryid> *)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主要是通过键值路径获得相应的属性,并且可以获得私有属性
那么它获取路径的顺序是什么呢
- (NSString *)getName;
- (NSString *)name;
- (NSString *)isName;
首先会依次查找这三个方法,当然既然声明的是属性,那么系统就默认实现了getter方法,所以会在第一步就找到.
那么如果这三个方法都没有找到呢
因为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机制的
切记,添加了监看一定要移除监看