前缀:
从本章开始,连续三章介绍如何实现iOS应用数据的快速缓存。
其中,第一章讲如何将JSON转化成模型对象,
第二章讲如何实现模型的自动化归档,
第三章讲快速缓存的实现。
第一章 ios JSON对象转化成模型
iOS中官方介绍的应用架构模式是MVC模式,也就是model- view - controller
通常model 是指用户定义的一些属性数据,比如姓名,年龄,学校等等。这些数据
通常会从服务器获取,从服务器获取后,得到JSON对象。这里就介绍如何将一个
JSON对象转化成对应的模型。
比如定义一个学生的模型。
@interface:NSObject
@property(nonatomic.strong) NSString *name;
@property(nonatomic.strong) NSString *age;
@property(nonatomic.strong) NSString *grade;
@property(nonatomic.strong) NSString *className;
@end;
当前有一个Json对象如下
@{@"name":@"peter",
@"age":@"16",
@"grade":@"3",
@className:@"五年纪一班"
}
而把上述JSON对象转化成相关模型的方法
其实有两种。
1. 在上述模型的实现中,实现JSON转化成模型的方法
+(Student*)initWithDic:(NSDictionary*)dic
{
Student *obj = [Student new];
obj.name = dic[@"name"];
obj.age = dic[@"age"];
obj.grade = dic[@"grade"];
obj.className = dic[@"className"];
return obj;
}
上面这样写是没问题的。
如果有更高效的方法,作为NSObject的扩展,不用每一个模型都写字典-》模型多好。
事实上这是可以实现的。下面说说实现的两个核型方法。
1.
调用runtime 的
class_copyPropertyList()
函数获取模型类的属性列表 array;
2.
便利array中的属性名,并查找对应于NSDictionary中的数据
如果有数据,调用setValue:forKey:方法给该属性赋值,
如果没有数据,则不赋值。
归根到底不外乎上面1、2两个步骤。
下面将NSObject的扩展,也就是从字典转化成模型的代码贴出来。如下:
-(id)initFromDic:(NSDictionary *)dic
{
if (self.class == NSObject.class) {
return nil;
}
else {
self = [self init];
}
if (self) {
Class currentClass = self.class;
NSMutableArray *propertyList = [[NSMutableArray alloc] init];
NSMutableArray *attributeNameList = [[NSMutableArray alloc] init];
while (currentClass && currentClass != NSObject.class)
{
unsigned int count = 0;
objc_property_t *pList = class_copyPropertyList(currentClass, &count);
if (count > 0)
{
for (int i = 0; i < count; i++)
{
NSString *propertyString = [NSString stringWithUTF8String:property_getName(pList[i])];
[propertyList addObject:propertyString];
NSString *attributeString = [NSString stringWithUTF8String:property_getAttributes(pList[i])];
[attributeNameList addObject:attributeString];
}
}
free(pList);
currentClass = class_getSuperclass(currentClass);
}
if (propertyList.count == 0) {
return self;
}
for (int i=0; i<propertyList.count ; i++) {
NSString *key = propertyList[i];
NSString *propertyType = [self getClassNameFromPropertyName:attributeNameList[i]];
id obj = [dic objectForKey:key];
if (obj == nil) {
continue;
}
if (propertyType == nil) {
[self setValue:obj forKey:key];
}
else if (([propertyType isEqualToString:@"NSMutableArray"] || [propertyType isEqualToString:@"NSArray"])
&& [obj isKindOfClass:[NSArray class]]) {
SEL classNameMethod = NSSelectorFromString(@"classNameForKeys");
if ([self respondsToSelector:classNameMethod]) {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
NSDictionary *classNameDic = (NSDictionary*)[self performSelector:classNameMethod];
Class propertyClass = [classNameDic objectForKey:key];
if (propertyClass) {
NSMutableArray *objArray = [[NSMutableArray alloc] init];
for (NSDictionary *objDic in obj) {
id transferedObj = [propertyClass objectFromDic:objDic];
if (transferedObj) {
[objArray addObject:transferedObj];
}
}
[self setValue:objArray forKey:key];
}
else {
[self setValue:obj forKey:key];
}
}
else {
[self setValue:obj forKey:key];
}
}
else {
Class keyClass = NSClassFromString(propertyType);
if (keyClass) {
id transferedObj = [keyClass objectFromDic:obj];
if (transferedObj) {
[self setValue:transferedObj forKey:key];
}
}
}
}
}
return self;
}
-(NSString *)getClassNameFromPropertyName:(NSString*)name
{
if (name == nil) {
return nil;
}
NSString * className = nil;
if ([[name substringWithRange:NSMakeRange(1, 1)] isEqualToString:@"@"]) {
NSString *subRangeString = [name substringWithRange:NSMakeRange(3, 3)];
if ([subRangeString isEqualToString:@"NSA"] || [subRangeString isEqualToString:@"NSM"]) {
className = @"NSArray";
}
else {
NSString *otherSystemString = [name substringWithRange: NSMakeRange(3, 2)];
if ([otherSystemString isEqualToString:@"NS"]) {
className = nil;
}
else {
className = [[name componentsSeparatedByString:@"\""] objectAtIndex:1];
}
}
}
return className;
}
Demo 下载地址为:http://download.csdn.net/download/j_akill/9118955