KVC键值编码:
KVC的操作方法由NSKeyValueCoding协议提供,而NSObject就实现了这个协议,也就是说ObjC中几乎所有的对象都支持KVC操作,常用的KVC操作方法如下:
动态设置: setValue:属性值 forKey:属性名(用于简单路径)、setValue:属性值 forKeyPath:属性路径(用于复合路径,例如Person有一个Account类型的属性,那么person.account就是一个复合属性)
动态读取: valueForKey:属性名 、valueForKeyPath:属性名(用于复合路径)
下面来看看几个例子就会明白KVC的好处了
场景一:给一个student的name和age赋值
@interface Student : NSObject
@property (nonatomic, assign) int age;
@property (nonatomic, copy) NSString *name;
@end
//不使用KVC时
NSDictionary *dic = @{@"name":@"张三",@"age":@20};
Student *sudent = [[Student alloc] init];
student.name = dic[@"name"];
student.age = dic[@"age"];
//这只是自己定义的简单的字典,用起来还不算复杂,要是在项目开发过程中会有很多的属性,再这样一个个去赋值显得麻烦很多
//使用kvc赋值
//在Student.h文件中增加一个自定义初始化的方法
- (instancetype)initWithDic:(NSDictionary *)dic;
//student.m中实现该方法
#import "Student.h"
@implementation Student
- (instancetype)initWithDic:(NSDictionary *)dic {
if (self = [super init]) {
[self setValuesForKeysWithDictionary:dic];
}
return self;
}
//在进行赋值的时候就只需要调用一个初始化方法即可,不在需要额外的设置
Student *student = [[Student alloc] initWithDic:dic];
NSLog(@"student.name = %@, student.age = %d",student.name, student.age);
@end
场景二.复合路径的赋值方法
#import "Person.h"
@class Account;
@interface Person : NSObject {
@private //通过KVC私有属性一样可以在外界赋值
int _age;
}
@property (nonatomic, copy) NSString *name;
@property (nonatomic, strong) Account *account; //账户
@end
//假如人有个账户
@interface Account : NSObject
@property (nonatomic, assign) float blance; //余额
@end
//主要实现代码
Person *person1 = [[Person alloc] init];
//setValue:属性值 forKey:属性名(用于简单路径
[person1 setValue:@"Kenshin" forKey:@"name"];
[person1 setValue:@28 forKey:@"age"];//注意即使一个私有变量仍然可以访问
NSLog(@"person1's name is :%@, age is %@",person1.name, [person1 valueForKey:@"age"]);
//按路径赋值
person1.account = [[Account alloc] init];
//setValue:属性值 forKeyPath:属性路径(用于复合路径
[person1 setValue:@10000.0 forKeyPath:@"account.blance"];
NSLog(@"person1's balance is %.2f",[[person1 valueForKeyPath:@"account.blance"] floatValue];
场景三:赋值字典转模型对象
#import
@interface Teacher : NSObject
@property (nonatomic, copy) NSString *teacherName;
//老师下有许多学生
@property (nonatomic, strong) NSArray *students;
//初始化方法
- (instancetype)initWithWithDic:(NSDictionary *)dic;
@end
#import "Teacher.h"
#import "Student.h"
@implementation Teacher
- (instancetype)initWithWithDic:(NSDictionary *)dic {
if (self = [super init]) {
[self setValue:dic[@"teacherName"] forKey:@"teacherName"];
NSArray *array = dic[@"students"];
NSMutableArray *students = [NSMutableArray array];
for (NSDictionary * dic in array) {
Student *student = [[Student alloc] initWithDic:dic];
[students addObject:student];
}
[self setValue:students forKey:@"students"];
}
return self;
}
#import
@interface Student : NSObject
@property (nonatomic, assign) int age;
@property (nonatomic, copy) NSString *name;
- (instancetype)initWithDic:(NSDictionary *)dic;
@end
#import "Student.h"
@implementation Student
- (instancetype)initWithDic:(NSDictionary *)dic {
if (self = [super init]) {
[self setValuesForKeysWithDictionary:dic];
}
return self;
}
@end
//模型转换实现代码
NSDictionary *dic = @{@"teacherName":@"王麻子",
@"students":@[@{@"name":@"张三",
@"age":@20},
@{@"name":@"李四",
@"age":@30}
]};
Teacher *teacher = [[Teacher alloc] initWithWithDic:dic];
NSLog(@"teacher = %@, teacher.name = %@", teacher, teacher.teacherName);
Student *student = teacher.students[0];
NSLog(@"student.name = %@, student.age = %d",student.name, student.age);
打印效果如下:
2016-09-12 14:25:07.539 KCVAndKVO[3780:1519551] teacher = 0x100701540>, teacher.name = 王麻子
2016-09-12 14:25:07.540 KCVAndKVO[3780:1519551] student.name = 张三, student.age = 20
Program ended with exit code: 0
KVO键值监听
//Account.h
#import
@interface Account : NSObject
@property (nonatomic, assign) float blance; //余额
@end
//Person.h
#import
@class Account;
@interface Person : NSObject {
@private
int _age;
}
@property (nonatomic, copy) NSString *name;
@property (nonatomic, strong) Account *account; //账户
/**
* 显示人员信息
*/
- (void)showMessage;
@end
//Person.m
#import "Person.h"
#import "Account.h"
@implementation Person
- (void)showMessage {
NSLog(@"name = %@, age = %d",_name, _age);
}
#pragma mark -- 设置人员账户
- (void)setAccount:(Account *)account {
_account = account;
//添加对Account的监听
[self.account addObserver:self forKeyPath:@"blance" options:NSKeyValueObservingOptionNew context:nil];
}
#pragma mark -- 重写observeValueForKeyPath方法,当账户余额变化后此处获得通知
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context {
if ([keyPath isEqualToString:@"blance"]) {//这里指出了blance属性
NSLog(@"keyPath = %@, object = %@, newValue = %.2f, context = %@", keyPath, object, [[change objectForKey:@"new"] floatValue], context);
}
}
#pragma mark -- 重写销毁的方法
- (void)dealloc {
[self.account removeObserver:self forKeyPath:@"blance"];
}
@end
//实现代码:
Person *person1 = [[Person alloc] init];
person1.name = @"Kenshin";
Account *account = [[Account alloc] init];
account.blance = 1000000.0;
person1.account = account;
account.blance = 20000000.0; //注意执行到这一步会触发监听器回调observeValueForKeyPath方法打印相关信息
//打印结果如下:2016-09-12 15:15:55.612 KCVAndKVO[3812:1725219] keyPath = blance, object = , newValue = 20000000.00, context = (null)
Program ended with exit code: 0
这篇文章只介绍KVC和KVO的基本使用,帮助理解和使用,如有错误的地方还请指正。