本文详细介绍在iOS开发中对KVC使用的一些心得体会,希望对阅读者有帮助,如有疏漏之处望指正,谢列位看官。
1.利用KVC给模型属性赋值用 [model setValuesForKeysWithDictionary:dict]
+ (instancetype)statusWithDict:(NSDictionary *)dict {
id obj = [[self alloc] init];
[obj setValuesForKeysWithDictionary:dict];
return obj;
}
(1)这个方法的底层通过调用 enumerateKeysAndObjectsUsingBlock: 一个个地取出字典当中的key,判
断调用对象model 有没有setKey(就是看调用对象有没有这个属性的set方法)通过respondsToSelector:
判断,如果有,直接在set方法中将value赋值给属性
(2)如果没有,看有没有带下划线的成员变量 _key,如果有,直接进行赋值
(3)如果没有,看有没有不带下划线的成员变量 key,如果有,直接进行赋值
(4)都没有,表示在对象当中没有找到对应的成员变量,会报错
2.两个使用前提:
(1)字典中的键名必须要和模型中的属性名都保持一致
(2)保证模型中的属性个数不能少于字典中的键值对的个数,如果字典中的键值对个数多于模型的属性个数,重写setValueforUndefinedKey:
3.使用场景
(1)赋值 setValue: forKeyPath:
相比 setValue: forKey: 可以通过路径取值,赋值
Person *p = [[Person alloc] init];
Dog *dog = [[Dog alloc] init];
p.dog = dog;
p.name = @"张三";
p.age = 18;
NSLog(@"%@-----%d",p.name, p.age);
// 1.kvc的赋值
[p setValue:@"李四" forKeyPath:@"name"];
[p setValue:@"20" forKeyPath:@"age"];
[p setValue:@"旺财" forKeyPath:@"dog.name"];
NSLog(@"%@-----%d------%@",p.name, p.age,dog.name);
(2)取值 valueForKeyPath:
// 2.kvc的取值 能够一次拿到所有对象的同一个属性
Person *p1 = [[Person alloc] init];
p1.name = @"a";
p1.age = 18;
Person *p2 = [[Person alloc] init];
p2.name = @"b";
p2.age = 19;
Person *p3 = [[Person alloc] init];
p3.name = @"c";
p3.age = 20;
NSArray *persons = @[p1, p2, p3];
NSLog(@"%@",[persons valueForKeyPath:@"p1.age"]);// NSLog(@"%@-----%d",[p valueForKeyPath:@"name"],[[p valueForKeyPath:@"age"] intValue]);
(3)模型转字典 dictionaryWithValuesForKeys:
// 3.模型转字典
Person *p = [[Person alloc] init];
p.name = @"tom";
p.age = 18;
NSDictionary *dict = [p dictionaryWithValuesForKeys:@[@"name",@"age"]];
NSLog(@"%@",dict);
属性较多的处理方式:
#import <objc/runtime.h> 运行时的框架
//把自定义对象的数组,所有的对象都转换成字典
NSMutableArray *mArray = [NSMutableArray arrayWithCapacity:2];
for (HMVideo *video in array)
{
// 以下为改良代码***********************************
unsigned int iCount = 0;
// unsigned int pCount = 0;
Ivar *iList = class_copyIvarList([HMVideo class], &iCount);
NSLog(@"成员变量数量%u", iCount);
// NSLog(@"属性数量%u", pCount);
NSMutableArray *arrayM = [NSMutableArray arrayWithCapacity:iCount];
// 遍历数组
for (int i = 0; i < iCount; i++)
{
// 成员变量名称
const char *name = ivar_getName(iList[i]);
[arrayM addObject:[NSString stringWithUTF8String:name]];
}
NSLog(@"------------>%@", arrayM);
// 释放对象
free(iList);
NSDictionary *dic = [video dictionaryWithValuesForKeys:arrayM];
[mArray addObject:dic];
}
NSData *data = [NSJSONSerialization dataWithJSONObject:mArray options:0 error:NULL];
[self postJSON:data];
(4)字典转模型 setValuesForKeysWithDictionary:
4.如果解析网络数据之后的字典中有一部分键值模型中不需要,可以重写
- (void)setValue:(nullable id)value forUndefinedKey:(NSString *)key;
5.解析之后的字典中有键值为id ,可以使用KVC进行赋值
6.解析之后的字典中的键值有int等数据类型关键字处理方式:
-(void)setValue:(id)value forUndefinedKey:(NSString *)key
{
if ([key isEqualToString:@"int"]) {
self.intxxx = value;
}
}
7.KVC的方法是 NSObject的方法 写在(NSKeyValueCoding)分类中
8.多重模型的嵌套
- (void)setValue:(id)value forKey:(NSString *)key {
// 判断 key 是否是 user
if ([key isEqualToString:@"user"]) {
self.user = [HMUser userWithDict:value];
return;
}
// 判断 key 是否是 retweeted_status
if ([key isEqualToString:@"retweeted_status"]) {
self.retweeted_status = [HMStatus statusWithDict:value];
return;
}
// 判断 key 是否是 pic_urls
if ([key isEqualToString:@"pic_urls"]) {
NSMutableArray *urls = [NSMutableArray array];
// 遍历数组,生成 url 数组
for (NSDictionary *dict in value) {
[urls addObject:[NSURL URLWithString:dict[@"thumbnail_pic"]]];
}
self.pic_urls = urls.copy;
return;
}
!!![super setValue:value forKey:key];
}