美味不用等4.0版本数据管理类设计简介

02/16/2016 13:54 下午 posted in  apple
Controller-->Manager: Request
Note left of Manager: 多个管理类进行数据处理
Manager->Controller:

Note right of Manager: HTTP,Cache,数据处理
Manager->Controller: Model
Controller->View: Data

一直想总结一下自己对一个项目工程架构的经验,在我看来无论是MVC,还是MVVM,其实都是为了将业务数据与具体的UI分离开,这个UI 不单单是具体的View也是UIController,要达到数据的低耦合,降低各模块的依赖,必须要使用一个中间层来管理和数据处理,一直以来我一直使用MVC的基础设计结构,但是我所理解的与之稍有出入。

MVC的概念指的是模型-控制器-视图,而在我看来,如果单一的使用控制器来管理诸多业务,类似网络请求,缓存,通知等,会造成控制器的臃肿和请求的散乱不便于管理,所以我对M的理解更倾向于Manager,当然在某种程度上也可以理解成为管理类和模型类的结合。管理类负责各工具类的业务调用和对结果数据的封装整理,存储,和下发给控制器,这里工具类是最基础的框架封装,比如工程中的对AFNetworking网络框架的的二次封装NWOperationManager,

##Manager管理类

数据请求管理结构

  1. 封装网络请求工具类|NWOperationManager
    这里我使用的是AFNetworking作为网络请求框架,继承它进行一些数据的基础封装。

Screen Shot 2016-02-16 at 15.28.45

注:目前该框架使用的是2.6.3,所以依然继承的是AFHTTPRequestOperationManager

其中回调的block为:

//Block
typedef void (^OperationCompleteBlock)(AFHTTPRequestOperation *operation, NWResult *result);

NWResult是针对服务器返回的数据结构的一个最基础的封装:

Screen Shot 2016-02-16 at 15.31.30

  1. 缓存工具类|NWCache
    NWOperationManager是一个网络请求基础工具类,它实现了网络请求的GET,POST等请求功能,同时也实现了缓存管理,当然如果和服务器进行配合可以较好的实现缓存详情参考:iOS网络缓存扫盲篇,但是目前服务器还未有该功能设计,而且由于该工程在最初的版本的时候是没有缓存设计的,是后来功能需求增加,所以需要一个缓存工具来实现,NWCache缓存设计的初步思想如下:
st=>start: 发起数据请求
e=>end: 数据
op=>operation: 本地缓存
op1=>operation: 发起网络请求
op2=>operation: 存储数据
cond=>condition: 缓存有效?

st->op->cond
cond(yes)->e(left)

cond(no)->op1->e
op1->op2(left)->e

NWCache类包含缓存的存储有效时间,和存储路径等作为最底层的工具封装。在网络模块中缓存的实现是请求工具类中处理的,管理类中只负责具体请求的缓存要求,
在请求工具类中其中一个基础接口是:

- (AFHTTPRequestOperation *)requestURL:(NSString *)URLString
                               inQueue:(dispatch_queue_t)queue
                               inGroup:(dispatch_group_t)group
                            HttpMethod:(HttpMethod)method
                            parameters:(NSDictionary *)parameters
                    cacheBodyWithBlock:(void (^)(id<NWCacheArgumentProtocol> cacheArgumentProtocol))block
                operationCompleteBlock:(OperationCompleteBlock)completeBlock;

NWCacheArgumentProtocol 是一个缓存的配置协议:

@protocol NWCacheArgumentProtocol <NSObject>
- (void)cacheResponseWithIgnoreCache:(BOOL)ignoreCache
                      supportOffLine:(BOOL)supportOffLine
                  cacheTimeInSeconds:(NSInteger)cacheTimeInSeconds;
@end
@interface NWCacheArgument : NSObject<NWCacheArgumentProtocol>
@property (nonatomic, strong, readonly) NSString *key;
/** 忽略缓存直接请求*/
@property (nonatomic, assign) BOOL ignoreCache;
/** 是否支持离线缓存,默认不支持*/
@property (nonatomic, assign) BOOL supportOffLine;
@property (nonatomic, assign) NSInteger cacheTimeInSeconds;

- (id)initWithKey:(NSString *)key;
@end

数据管理类中某一个请求是这样的:

- (void)fetchReferencesShopsWithNextCursor:(NSInteger)nextCursor
                                  useCache:(BOOL)useCache
                               expiredTime:(NSInteger)expiredTime
                             completeBlock:(CompleteBlock)completeBlock

可以看到该方法中有两个参数是有关缓存的,是否缓存和过期时间,在具体实现的时候有一个方法来处理这两个参数

#pragma mark private base method
- (void)httpRequestMethod:(HttpMethod)method
                      url:(NSString *)url
               parameters:(NSDictionary *)parameters
                 useCache:(BOOL)useCache
              expiredTime:(NSInteger)expiredTime
     requestCompleteBlock:(RequestCompleteBlock)requestCompleteBlock{
    AFHTTPRequestOperation *opreration = nil;
    NSMutableDictionary *param = [self commonArgumentWithUserParameters:parameters];
    DDLogInfo(@"%@:%@",url,param);
    opreration = [[NWOperationManager sharedClient] requestURL:url
                                                       inQueue:self.httpRequest_queue_t
                                                       inGroup:self.httpRequest_group_t
                                                    HttpMethod:method
                                                    parameters:param
                                            cacheBodyWithBlock:^(id<NWCacheArgumentProtocol> cacheArgumentProtocol) {
                                                [cacheArgumentProtocol cacheResponseWithIgnoreCache:!useCache supportOffLine:YES cacheTimeInSeconds:expiredTime];
                                            } operationCompleteBlock:^(AFHTTPRequestOperation *operation, NWResult *result) {
                                                [self requestURI:url operationCompleteBlock:requestCompleteBlock result:result];
                                                DDLogInfo(@"%@:%@",url,result.response);
                                            }];
}

cacheBodyWithBlock该Block就是配置该请求的缓存设置的,

该设计在没有大改早先控制器方法调用的基础上只是修改了 管理类的请求工具调用和增加缓存工具类就实现了自定义的网络请求缓存,目前还能够满足需求。

当然在具体实现中遇到的一些问题是要避免的,首先在缓存数据的时候是有一个Key是很关键的,该key由接口和识别参数,是该参数是需要注意分页中的页码和诸如经纬度等,避免出错。

总之数据管理类的功能是管理和处理数据请求的,解放控制器,让控制器不再进行数据逻辑处理,控制器只负责简单的数据请求,它只要数据不必管这个数据是来自缓存还是来此云端。数据管请求工具返回的数据是简单封装的原始数据(NWResult),然后数据管理进行数据的再封装转为model返回给控制器,当要进行UI展示的时候将数据传输给视图View,这里的数据不建议是model传输,因为要保证解耦,不能让视图与model过多的联系,所以建议以原始数据的形式进行传输。