字典转模型 & 泛型数组
- 开发中,为了简化控制器和视图中的代码编写,通常是不针对字典直接操作的。
- 为了简化程序员的开发,苹果提供了 KVC(key value coding) 技术
-
KVC
又被称为苹果开发的大招
目标
- 掌握 KVC 的字典转模型和模型转字典方法
- 字典转模型
setValuesForKeysWithDictionary
- 使用自定的字典转换成模型
- 使用细节:
- 如果字典中有对象中不存在的 key,会崩溃
- 如果对象属性中有字典中不存在的 key,没有反应
- 本质上就是遍历字典 key,然后一个一个的设置数值
- 模型转字典
dictionaryWithValuesForKeys
- 使用指定的属性列表,将模型转换成字典
- 注意:字典转模型和模型转字典,默认都只能转换一级模型,嵌套模型还需要增加代码
- 有关 KVC 字典转模型的实现原理,后续课程会讲
- 掌握代码块定义技巧
~/Developer/Xcode/UserData/CodeSnippets
- 不需要的代码块直接选中按删除键可以删除
- 掌握数组
泛型
的使用技巧,Xcode 7
提供
- 数组是以下标来访问内部元素的
- 尽管 OC 中的数组可以存放任意对象,但是一个数组中保存的元素类型通常是一致的
- 在定义泛型数组时,可以增加
<类 *>
的格式指定数组内部存放元素的类型 - 格式:
NSMutableArray <Person *>*arrayM
- 指定了类型之后:
- 如果向数组中添加其他类型的对象会报警告,提前发现错误
- 可以直接通过
.
语法获取数组内部元素的属性 - 控制台不支持
.
语法,仍然需要使用[]
操作步骤
准备模型 —— 代码块演练
由于是复习知识点,中间穿插一下定义代码块,提高开发效率的技巧
- 新建
Person
模型继承自NSObject
- 定义模型属性
@interface Person : NSObject
@property (nonatomic, copy) NSString *name;
@property (nonatomic, assign) NSInteger age;
@end
介绍代码块定义
- 定义模型构造函数
#pragma mark - 模型构造函数
+ (instancetype)personWithDict:(NSDictionary *)dict;
- (instancetype)initWithDict:(NSDictionary *)dict;
演示构造函数的代码块定义
介绍代码块维护
- 不需要的代码块直接选中按删除键可以删除
- 保存位置
~/Developer/Xcode/UserData/CodeSnippets
- 复制备课代码块
实现构造函数,介绍 KVC 的两个大招
- 字典转模型
setValuesForKeysWithDictionary
,简化开发- 模型转字典
dictionaryWithValuesForKeys
,简化调试
- 在 ViewController 中导入头文件
#import "Person.h"
- 在 viewDidLoad 方法中实例化模型并且测试
- (void)viewDidLoad {
[super viewDidLoad];
NSDictionary *dict = @{@"name": @"zhangsan", @"age": @18};
Person *p1 = [Person personWithDict:dict];
NSLog(@"%@ %@ %zd", p1, p1.name, p1.age);
}
- 传统的设置方法
+ (instancetype)personWithDict:(NSDictionary *)dict {
return [[self alloc] initWithDict:dict];
}
- (instancetype)initWithDict:(NSDictionary *)dict {
self = [super init];
if (self) {
// 方法 1,直接设置,基本数据类型需要转换
_name = dict[@"name"];
_age = [dict[@"age"] integerValue];
}
return self;
}
- 使用 KVC 设置属性
- (instancetype)initWithDict:(NSDictionary *)dict {
self = [super init];
if (self) {
// 1. 方法 1 直接设置数值
// _name = dict[@"name"];
// _icon = dict[@"icon"];
// 方法 2 使用 KVC 设置数值
[self setValue:dict[@"name"] forKey:@"name"];
[self setValue:dict[@"icon"] forKey:@"icon"];
}
return self;
}
- 方法 3,遍历字典 设置数值
// 方法 3,遍历字典 设置数值
for (NSString *key in dict) {
id value = dict[key];
[self setValue:value forKey:key];
}
setValuesForKeysWithDictionary
// 方法 4,简化方法
[self setValuesForKeysWithDictionary:dict];
-
setValuesForKeysWithDictionary
方法,本质上就是遍历字典 - 然后依次调用
[self setValue:value forKey:key];
设置数值
实现 description
简化调试
- 默认情况下,实例化一个对象之后,打印只能输出对象的类型和指针
- 为了方便程序的开发调试,在定义模型是通常建议实现一下
description
- (NSString *)description {
NSArray *keys = @[@"name", @"age"];
return [self dictionaryWithValuesForKeys:keys].description;
}
-
dictionaryWithValuesForKeys
方法会遍历给定的 keys 数组 - 顺序取出每一个
key
对应属性的value
- 依次添加到字典中
在开发
模型
时,实现description
是一个好习惯
泛型数组
- 数组是以下标来访问内部元素的
- 尽管 OC 中的数组可以存放任意对象,但是一个数组中保存的元素类型通常是一致的
- 在定义泛型数组时,可以增加
<类 *>
的格式指定数组内部存放元素的类型 - 格式:
NSMutableArray <Person *>*arrayM
- 指定了类型之后:
- 如果向数组中添加其他类型的对象会报警告,提前发现错误
- 可以直接通过
.
语法获取数组内部元素的属性 - 控制台不支持
.
语法,仍然需要使用[]
- 示例代码
NSMutableArray <Person *>*arrayM = [NSMutableArray array];
NSDictionary *dict1 = @{@"name": @"zhangsan", @"age": @18};
NSDictionary *dict2 = @{@"name": @"lisi", @"age": @108};
[arrayM addObject:[Person personWithDict:dict1]];
[arrayM addObject:[Person personWithDict:dict2]];
NSLog(@"%@", arrayM[1].name);