KVC键值编码
键值编码中基本使用-valueForKey:和-setValue:forKye:方法。你可以像对象发送消息并且传递你想要访问的熟悉名称的键值作为参数。
KVC方法会首先查找以参数命名的getter、setter方法,如果没有提供getter、setter方法,KVC方法会直接寻找_name和name的实例变量。
// book.h
@interface ZZBook : NSObject
@property (nonatomic,copy) NSString *name;
@end
// book.m
@implementation ZZBook
@end
// person.h
@class ZZBook;
@interface ZZPerson : NSObject
@property (nonatomic,copy) NSString *name;
@property (nonatomic,assign) int age;
@property (nonatomic,strong) ZZBook *book;
@end
// person.m
@implementation ZZPerson
@end
// main.m
int main(int argc, const char * argv[]) {
ZZPerson *p1 = [[ZZPerson alloc] init];
p1.name = @"人1";
p1.age = 18;
ZZBook *book = [[ZZBook alloc] init];
book.name = @"书1";
p1.book = book;
ZZPerson *p2 = [[ZZPerson alloc] init];
// KVC赋值
[p2 setValue:@"人1" forKey:@"name"];
[p2 setValue:@19 forKey:@"age"];
ZZPerson *p3 = [[ZZPerson alloc] init];
p3.name = @"人3";
p3.age = 20;
// 取值
NSString *name = [p1 valueForKey:@"name"];
int age = [[p1 valueForKey:@"age"] intValue];
NSLog(@"%@",name);
NSDictionary *dic = [p1 dictionaryWithValuesForKeys:@[@"name",@"age"]];
NSLog(@"%@",dic);
NSArray *persons = @[p1,p2,p3];
// 整体访问
NSArray *names = [persons valueForKey:@"name"];
NSLog(@"%@",names);
// 带路径
NSLog(@"%@",[p1 valueForKeyPath:@"book.name"]);
return 0;
}
注意:KVC需要解析字符串来计算答案,说以运行效率会比较低,而且编译器无法做错误检查,有可能会在运行时出错。
KVO键值观察者
可以监听一个对象的属性,当这个对象的属性发生变化时,会收到一个消息。
//person.h
@interface ZZPerson : NSObject
@property (nonatomic, copy) NSString *name;
@property (nonatomic, copy) NSString *add;
@end
//person.m
@implementation ZZPerson
@end
//viewControl.m
@interface ViewController ()
@property (nonatomic, strong) ZZPerson *p;
@end
@implementation ViewController
- (ZZPerson *)p{
if (_p == nil) {
_p = [[ZZPerson alloc] init];
_p.name = @"名字";
_p.add = @"地址1";
}
return _p;
}
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
[self.p addObserver:self forKeyPath:@"add" options:NSKeyValueObservingOptionOld context:nil];
}
//实现KVO方法
/**
* 当监控的某个属性的值改变了就会调用
*
* @param keyPath 属性名(哪个属性改了?)
* @param object 哪个对象的属性被改了?
* @param change 属性的修改情况(属性原来的值、属性最新的值)
* @param context void * == id
*/
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context {
NSString *name = [object valueForKey:@"name"];
NSString *add = [object valueForKey:@"add"];
NSLog(@"%@ has a new add: %@", name, add);
NSLog(@"%@", change);
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
self.p.add = @"地址2";
}
- (void)dealloc
{
// 移除观察者
[self.p removeObserver:self forKeyPath:@"age"];
}
@end
先添加一个对对象Person的add属性的观察,观察者为控制器对象。
[self.p addObserver:self forKeyPath:@"add" options:NSKeyValueObservingOptionOld context:nil];
实现KVO方法
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context;
当控制器收到触摸事件的时候,改变了person的add属性,person会向控制器发送KVO的消息,然后调用方法。