Objective-C KVC,KVO简单使用

🌰  :

首先创建一个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:(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主要是通过键值路径获得相应的属性,并且可以获得私有属性

那么它获取路径的顺序是什么呢

- (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机制的

切记,添加了监看一定要移除监看

 

posted on 2018-02-05 11:32  咿呀呀呀呀咿  阅读(136)  评论(0编辑  收藏  举报

导航