KVC(Key-value coding)键值编码,就是指iOS的开发中,可以允许开发者通过Key名直接访问对象的属性,或者给对象的属性赋值。而不需要调用明确的存取方法。这样就可以在运行时动态地访问和修改对象的属性。而不是在编译时确定,这也是iOS开发中的黑魔法之一。
赋值过程:
1. 先找相关方法 set<key>: , _set<key>: , setIs<key>: ;
2.若没有相关方法,则会调用+(BOOL)accessInstanceVariablesDirectly (判断是否可以直接访问变量)。
如果:NO, 那么直接执行KVC 的 setValue:forUndefinedKey方法(系统异常,未定义key)。
如果: YES, 你什么继续寻找相关变量 _<key> , _is<key> , <key> , is<key>。
3.若方法或者成员变量都不存在,则执行 setValue:forUndefindKey 方法,(默认抛出异常)。
4 如果赋值对象为nil , 则会调用setNilValueForKey:, (抛出异常)
取值过程:
1. 先找相关方法 get<key>: , <key>
2.若没有相关方法,则会调用+(BOOL)accessInstanceVariablesDirectly (判断是否可以直接访问变量)。
如果:NO, 那么直接执行KVC 的 value:forUndefinedKey方法(系统异常,未定义key)。
如果: YES, 你什么继续寻找相关变量 _<key> , _is<key> , <key> , is<key>。
3.若方法或者成员变量都不存在,则执行 value:forUndefindKey 方法,(默认抛出异常)。
异常处理:
1. setNilValueForKey: 赋值为空
2. (set)value:forUndefindKey Key值不存在
正确性验证:
调用 vaildateValue 返回bool, 工作原理如下:
1. 先找要验证的类中是否实现了方法-(BOOL)validate<key>:error: (此方法去验证要要争的对象的正确性)。
2 如果没有实现 -(BOOL)validate<key>:error 方法。 系统默认返回YES.
消息传递:
NSArray* arr = @[@"Monday", @"Tuesday", @"Wednesday"];
NSArray* lengthArr = [arr valueForKey:@"length"];
NSLog(@"每个元素的长度%@", lengthArr);
NSArray* lowercaseArr = [arr valueForKey:@"lowercaseString"];
NSLog(@"每个元素转小写%@", lowercaseArr);
聚合操作符:
@avg、@count、@max、@min、@sum
NSMutableArray* students = [NSMutableArray array];
for (int i = 0; i < 6; i++) {
TZPerson* student = [TZPerson new];
NSDictionary* dict = @{
@"name":@"Tom",
@"age":@(18+i),
@"nick":@"Cat",
@"height":@(1.65 + 0.02*arc4random_uniform(6)),
};
[student setValuesForKeysWithDictionary:dict];
[students addObject:student];
}
NSLog(@"%@", [students valueForKey:@"height"]);
/// 平均身高
float avg = [[students valueForKeyPath:@"@avg.height"] floatValue];
NSLog(@"%f", avg);
数组操作符:
去重 /不去重 @distinctUnionOfObjects @unionOfObjects
NSMutableArray* students = [NSMutableArray array];
for (int i = 0; i < 6; i++) {
TZPerson* student = [TZPerson new];
NSDictionary* dict = @{
@"name":@"Tom",
@"age":@(18+i),
@"nick":@"Cat",
@"height":@(1.65 + 0.02*arc4random_uniform(6)),
};
[student setValuesForKeysWithDictionary:dict];
[students addObject:student];
}
NSLog(@"%@", [students valueForKey:@"height"]);
NSArray* arr = [students valueForKeyPath:@"@distinctUnionOfObjects.height"];
NSLog(@"arr = %@", arr);
NSArray* arr1 = [students valueForKeyPath:@"@unionOfObjects.height"];
NSLog(@"arr1 = %@", arr1);
嵌套集合(array&set)操作
@distinctUnionOfArrays @unionOfArrays @distinctUnionOfSets(针对set)
NSMutableArray* students = [NSMutableArray array];
for (int i = 0; i < 6; i++) {
TZPerson* student = [TZPerson new];
NSDictionary* dict = @{
@"name":@"Tom",
@"age":@(18+i),
@"nick":@"Cat",
@"height":@(1.65 + 0.02*arc4random_uniform(6)),
};
[student setValuesForKeysWithDictionary:dict];
[students addObject:student];
}
NSMutableArray* students1 = [NSMutableArray array];
for (int i = 0; i < 6; i++) {
TZPerson* student = [TZPerson new];
NSDictionary* dict = @{
@"name":@"Tom",
@"age":@(18+i),
@"nick":@"Cat",
@"height":@(1.65 + 0.02*arc4random_uniform(6)),
};
[student setValuesForKeysWithDictionary:dict];
[students1 addObject:student];
}
// 嵌套数组
NSArray* nestArr = @[students, students1];
NSArray* arr = [nestArr valueForKeyPath:@"@distinctUnionOfArrays.height"];
NSLog(@" 二维数组合并去重arr = %@", arr);
NSArray* arr1 = [nestArr valueForKeyPath:@"@unionOfArrays.height"];
NSLog(@"二维数组合不去重arr1 = %@", arr1);
集合代理对象 (一对多)
// .h
@interface TZPerson : NSObject
@property (nonatomic, strong) NSString* name;
@property (nonatomic, assign) int age;
@property (nonatomic, strong) NSString* nick;
@property (nonatomic, assign) float height;
@property (nonatomic, assign) NSUInteger count;
@property (nonatomic, strong) NSMutableArray *penArr;
@end
//.m
@implementation TZPerson
- (NSUInteger) countOfBooks {
return self.count;
}
- (id) objectInBooksAtIndex:(NSUInteger)index {
return [NSString stringWithFormat:@"book %lu", index];
}
// 个数
- (NSUInteger) countOfPens {
return [self.penArr count];
}
// 是否包含这个成员对象
- (id) memberOfPens:(id)object {
return [self.penArr containsObject:object] ? object : nil;
}
// 迭代器
- (id) enumeratorOfPens {
return [self.penArr reverseObjectEnumerator];
}
@end
// ViewController
- (void)viewDidLoad {
[super viewDidLoad];
TZPerson* p = [TZPerson new];
p.count = 5;
NSLog(@"books = %@", [p valueForKey:@"books"]);
p.penArr = [NSMutableArray arrayWithObjects:@"pen0", @"pen1", @"pen2", @"pen3", nil];
NSSet* set = [p valueForKey:@"pens"];
NSLog(@"pens = %@", set);
NSEnumerator* enumerator = [set objectEnumerator];
NSString* str = nil;
while (str = [enumerator nextObject]) {
NSLog(@"%@", str);
}
}