NSObject有个扩展NSKeyValueCoding,所以所有的oc都都可以基于kvc进行属性的访问。先看一下kvc的各种操作方法的使用示例。
基本赋值操作
对于普通对象通过valueForKey:
和setValue:forKey:
进行读取。
LGPerson *person = [[LGPerson alloc] init];
// 一般setter 方法
person.name = @"LG_Cooci"; // setter -- llvm
person.age = 18;
person->myName = @"cooci";
NSLog(@"%@ - %d - %@",person.name,person.age,person->myName);
// 1:Key-Value Coding (KVC) : 基本类型 - 看底层原理
// 非正式协议 - 间接访问
[person setValue:@"KC" forKey:@"name"];
// 2:KVC - 集合类型
person.array = @[@"1",@"2",@"3"];
// 修改数组
// person.array[0] = @"100";
// 第一种:搞一个新的数组 - KVC 赋值就OK
NSArray *array = [person valueForKey:@"array"];
array = @[@"100",@"2",@"3"];
[person setValue:array forKey:@"array"];
NSLog(@"%@",[person valueForKey:@"array"]);
// 第二种
NSMutableArray *mArray = [person mutableArrayValueForKey:@"array"];
mArray[0] = @"200";
NSLog(@"%@",[person valueForKey:@"array"]);
字典操作
把字典中的key和对象的属性一一对应起来
- (void)dictionaryTest{
NSDictionary* dict = @{
@"name":@"Cooci",
@"nick":@"KC",
@"subject":@"iOS",
@"age":@18,
@"length":@180
};
LGStudent *p = [[LGStudent alloc] init];
// 字典转模型
[p setValuesForKeysWithDictionary:dict];
NSLog(@"%@",p);
// 键数组转模型到字典
NSArray *array = @[@"name",@"age"];
NSDictionary *dic = [p dictionaryWithValuesForKeys:array];
NSLog(@"%@",dic);
}
消息传递
对数组中每个对象发送消息,相当于遍历数据并调用相应方法
- (void)arrayMessagePass{
NSArray *array = @[@"Hank",@"Cooci",@"Kody",@"CC"];
NSArray *lenStr= [array valueForKeyPath:@"length"];
NSLog(@"%@",lenStr);// 消息从array传递给了string
NSArray *lowStr= [array valueForKeyPath:@"lowercaseString"];
NSLog(@"%@",lowStr);
}
聚合操作符
相当于遍历数组中的每个对象,取其对应字段组装成一个新的数组,然后针对该数组进行进一步的聚合处理,avg、count、sum等
- (void)aggregationOperator{
NSMutableArray *personArray = [NSMutableArray array];
for (int i = 0; i < 6; i++) {
LGStudent *p = [LGStudent new];
NSDictionary* dict = @{
@"name":@"Tom",
@"age":@(18+i),
@"nick":@"Cat",
@"length":@(175 + 2*arc4random_uniform(6)),
};
[p setValuesForKeysWithDictionary:dict];
[personArray addObject:p];
}
NSLog(@"%@", [personArray valueForKey:@"length"]);
/// 平均身高
float avg = [[personArray valueForKeyPath:@"@avg.length"] floatValue];
NSLog(@"%f", avg);
int count = [[personArray valueForKeyPath:@"@count.length"] intValue];
NSLog(@"%d", count);
int sum = [[personArray valueForKeyPath:@"@sum.length"] intValue];
NSLog(@"%d", sum);
int max = [[personArray valueForKeyPath:@"@max.length"] intValue];
NSLog(@"%d", max);
int min = [[personArray valueForKeyPath:@"@min.length"] intValue];
NSLog(@"%d", min);
}
数组操作符
相当于遍历数据中的元素,取其对应的字段组成新数组后,进行unionOfObjects、distinctUnionOfObjects操作
- (void)arrayOperator{
NSMutableArray *personArray = [NSMutableArray array];
for (int i = 0; i < 6; i++) {
LGStudent *p = [LGStudent new];
NSDictionary* dict = @{
@"name":@"Tom",
@"age":@(18+i),
@"nick":@"Cat",
@"length":@(175 + 2*arc4random_uniform(6)),
};
[p setValuesForKeysWithDictionary:dict];
[personArray addObject:p];
}
NSLog(@"%@", [personArray valueForKey:@"length"]);
// 返回操作对象指定属性的集合
NSArray* arr1 = [personArray valueForKeyPath:@"@unionOfObjects.length"];
NSLog(@"arr1 = %@", arr1);
// 返回操作对象指定属性的集合 -- 去重
NSArray* arr2 = [personArray valueForKeyPath:@"@distinctUnionOfObjects.length"];
NSLog(@"arr2 = %@", arr2);
}
嵌套集合(array&set)操作
相当于把嵌套的集合平铺开来当成一个集合后再进行操作
- (void)arrayNesting{
NSMutableArray *personArray1 = [NSMutableArray array];
for (int i = 0; i < 6; i++) {
LGStudent *student = [LGStudent new];
NSDictionary* dict = @{
@"name":@"Tom",
@"age":@(18+i),
@"nick":@"Cat",
@"length":@(175 + 2*arc4random_uniform(6)),
};
[student setValuesForKeysWithDictionary:dict];
[personArray1 addObject:student];
}
NSMutableArray *personArray2 = [NSMutableArray array];
for (int i = 0; i < 6; i++) {
LGStudent *person = [LGStudent new];
NSDictionary* dict = @{
@"name":@"Tom",
@"age":@(18+i),
@"nick":@"Cat",
@"length":@(175 + 2*arc4random_uniform(6)),
};
[person setValuesForKeysWithDictionary:dict];
[personArray2 addObject:person];
}
// 嵌套数组
NSArray* nestArr = @[personArray1, personArray2];
NSArray* arr = [nestArr valueForKeyPath:@"@distinctUnionOfArrays.length"];
NSLog(@"arr = %@", arr);
NSArray* arr1 = [nestArr valueForKeyPath:@"@unionOfArrays.length"];
NSLog(@"arr1 = %@", arr1);
}
- (void)setNesting{
NSMutableSet *personSet1 = [NSMutableSet set];
for (int i = 0; i < 6; i++) {
LGStudent *person = [LGStudent new];
NSDictionary* dict = @{
@"name":@"Tom",
@"age":@(18+i),
@"nick":@"Cat",
@"length":@(175 + 2*arc4random_uniform(6)),
};
[person setValuesForKeysWithDictionary:dict];
[personSet1 addObject:person];
}
NSLog(@"personSet1 = %@", [personSet1 valueForKey:@"length"]);
NSMutableSet *personSet2 = [NSMutableSet set];
for (int i = 0; i < 6; i++) {
LGStudent *person = [LGStudent new];
NSDictionary* dict = @{
@"name":@"Tom",
@"age":@(18+i),
@"nick":@"Cat",
@"length":@(175 + 2*arc4random_uniform(6)),
};
[person setValuesForKeysWithDictionary:dict];
[personSet2 addObject:person];
}
NSLog(@"personSet2 = %@", [personSet2 valueForKey:@"length"]);
// 嵌套set
NSSet* nestSet = [NSSet setWithObjects:personSet1, personSet2, nil];
// 交集
NSArray* arr1 = [nestSet valueForKeyPath:@"@distinctUnionOfSets.length"];
NSLog(@"arr1 = %@", arr1);
}
setValue:forKey:流程梳理
在我们调用[person setValue:@"xxx" forKey:@"name"]这行代码时,oc底层将经过以下几个步骤:
- 依次调用name的几个set方法,setName、_setName、setIsName,如果都没有进入步骤2
- 根据accessInstanceVariablesDirectly方法返回值判断是否需要进行实例变量转发流程,如果是则会依次对_name、_isName、name、isName进行赋值,如果否则进行步骤3
- 调用setValue:forUnderfineKey:方法,在这里开发者可以进行最后一次补救,否则就会崩溃
valueForKey流程梳理
在我们调用[person valueForKey:@"name"]这行代码时,oc底层将经过以下几个步骤:
- 依次调用name的几个get方法,getName、name、isName、_name,如果都没有进入步骤2
- 此时先判断是否集合类型,会判断是否有countOf、memberOf等方法,如果有则表示集合类型并进行方法调用后组装成对应类型的集合并返回,如果没有则进入步骤3
- 根据accessInstanceVariablesDirectly方法返回值判断是否需要进行实例变量转发流程,如果是则会依次尝试取_name、_isName、name、isName字段,如果否进入步骤4
- 调用valueForUndefinedKey:方法,在这里开发者可以进行最后一次补救,否则就会崩溃
网友评论