-
Notifications
You must be signed in to change notification settings - Fork 52
/
16.应用实战——数据组织(淘宝).txt
188 lines (131 loc) · 7.96 KB
/
16.应用实战——数据组织(淘宝).txt
1
数据组织 我想每个应用都会遇到这样的情况,通过向服务端请求取到的数据,如何组织,如何存放。下面列出了几种常用的做法,并会着重介绍第三种方法的实现。一,常用方法1,字典对象方法 字典对象方法应该是非常常用的了吧,就是从服务端取得数据解析之后,直接放到一个NSDictionary对象里。在使用的时候,通过NSDictionary的objectForKey方法取到对应数据。比如访问这样的链接【图 16-01】客户端拿到数据之后,解析赋值给一个NSDictionary类型。 NSDictionary *dic = [[request responseString] JSONValue]; NSLog(@"dic %@",dic); NSString *title = [dic objectForKey:@"title"]; NSString *price = [dic objectForKey:@"price"]; BOOL discount = [[dic objectForKey:@"discount"] boolValue]; NSLog(@"title %@",title); NSLog(@"price %@",price); NSLog(@"discount %d",discount);打印出日志【图 16-02】 这种方法优点是简单方便,易于操作。但是存在很多缺点,比如对特殊的数据类型需要进行特殊转换,就像上面的price和new,分别是字符串和布尔型。每次取数据都要用对应的key来取,这样就存在很多风险。如果很多地方要使用某一个key对应值的时候,每次都要取一遍,而且不利于复用。如果有其他的接口,也返回这样的数据结构,那么在另外一个地方也要写相同的解析代码。使用的时候也要写相同的获取代码。所以总结来说就是取值麻烦和复用度低的问题,那么要解决这两个问题,可以用第二个方法组织数据。2,类对象方法,手动设置变量。 类对象方法无非就是把返回的数据组织存放到一个自定义的类对象里面,这个class可以根据返回的结果设置成员变量。比如还是刚才的请求,可以把返回的数据存放在这样的一个类里面。@interface Model : NSObject@property (nonatomic, retain) NSString *title;@property (nonatomic, retain) NSString *price;@property (nonatomic, assign) BOOL discount;@end用服务端拿来的json,初始化这个Model。- (id)initWithData:(NSDictionary *)data { self = [super init]; if (self) { self.title = [data objectForKey:@"title"]; self.price = [data objectForKey:@"price"]; self.discount = [[data objectForKey:@"discount"] boolValue]; } return self;}这样一来,访问的时候就变得非常方便。跟上一个方法相比,访问的时候省去valueForKey方法,数据在一次拿到的时候得到了处理。而且有其他地方有用到相同的结构,可以直接使用这个Model。Model *model = [[Model alloc] initWithData:dic]; NSLog(@"title %@",model.title); NSLog(@"price %@",model.price); NSLog(@"discount %d",model.discount); 这种方法好处就在于可以复用,方便统一处理,也方便管理。但是问题又来了,如果我们处理的数据有很多key,那就要写很多[data objectForKey:@"xxx"]这样的代码,感觉就是一身无聊的体力活,而且有很多数据需要判断它是NSString类型,还是BOOL还是其他NSArray或者其他呢?可以参考下一个方法,也是我们使用的方法。3,类对象方法,自动设置变量。 写到这里,看方法2和方法3的名字,就可以知道区别了。一个是手动设置变量,一个是自动设置变量,手动设置就是要你去写objectForKey的key。那么如何自动让返回的数据对应到Model的成员变量呢?首先,我们把要解析的数据改的复杂一点,增加一个arry。我们访问这样的一个数据【图 16-03】现在我们要做的是,在初始化的时候让key找到它赋值的变量。只需要把初始化方法改为- (id)initWithData:(NSDictionary *)data { self = [super init]; if (self) { for (NSString *key in [data keyEnumerator]) { id val = [data objectForKey:key]; [self setValue:val forKey:key]; } } return self;}这样看起来就把方法2简化多了吧。不需要再根据不同类型进行转换,省去了一些判断,更省去了很多体力活。于是方便了之后我们就有很多设想,在第二部分介绍。第二部分 方法3的联想1,多种组合(字典,数组,字符串,布尔值) 现在方便用key去给变量赋值,那么多种数据类型就容易支持了。只要在声明变量的property的时候写清楚就可以了。比如方法3里面的例子,返回数据有NSArray,NSString和BOOL,只要代码表示清楚即可。@property (nonatomic, retain) NSString *title;@property (nonatomic, retain) NSString *price;@property (nonatomic, assign) BOOL discount;@property (nonatomic, retain) NSArray *city;2,更换key 之前在方法3里面我们发现,如果服务端返回的key是title,那么Model里的变量名也叫title。但是服务端经常会给key取一些objc关键字的名字,比如说id,new。这个时候怎么办呢,我们可以在存放数据时候做一个转化。 if ([key isEqualToString:@"id"]) { [self setValue:val forKey:@"itemId"]; } 但是这样写并不漂亮,我们可以在Model里面写一个keyMap的方法,让有对应的key在keyMap方法里面得到转化。3,类套类 类套类,就是一个数据Model里面还包含另外一种类型的数据Model。我觉得这个方法是亮点,使组织数据变得很方便。我们可以看这样的一个接口。【图 16-04】可以看到,city也可以存放在一个数据Model里面。那么要新建一个CityModel,我们可以模仿Model来写。然后修改一下Model的变量。是Model增加一个CityModel的变量。 @class CityModel;@interface Model : NSObject@property (nonatomic, retain) NSString *title;@property (nonatomic, retain) NSString *price;@property (nonatomic, assign) BOOL discount;//@property (nonatomic, retain) NSArray *city;//在此处添加一个CityModel@property (nonatomic, retain) CityModel *city;- (id)initWithData:(NSDictionary *)data;@end在实现的时候增加一个判断,判断这个key拿到的数据,是否需要用另外一种数据Model来存放,方法如下。- (Class)classForKey:(NSString *)key{ //当key是city的时候,返回需要转换的数据Model-CityModel if (key && [key isEqualToString:@"city"]) { return [CityModel class]; } return nil;}- (id)initWithData:(NSDictionary *)data { self = [super init]; if (self) { for (NSString *key in [data keyEnumerator]) { id val = [data objectForKey:key]; //如果是字典,判断是否需要转化为另外的数据Model if ([val isKindOfClass:[NSDictionary class]]) { Class type = [self classForKey:key]; if (type) { //如果也是一个类,那么就用这个类初始化它。 [self setValue:[[type alloc] initWithData:val] forKey:key]; } else { [self setValue:val forKey:key]; } } else { //无特殊情况还继续正常的赋值 [self setValue:val forKey:key]; } } } return self;}使用下面的代码Model *model = [[Model alloc] initWithData:dic]; NSLog(@"title %@",model.title); NSLog(@"price %@",model.price); NSLog(@"discount %d",model.discount); NSLog(@"city %@",model.city); CityModel *city = model.city; NSLog(@"city.fist %@",city.first); NSLog(@"second %@",city.second);打印出来的数据如下图。【图 16-05】通过这样的方法,就可以支持更复杂的结构。还可以做更多样的处理。不单单是这几种简单的处理,可以根据需求任意改变。