CBNetworking:源码分析
来源:互联网 发布:windows安装光盘图片 编辑:程序博客网 时间:2024/06/17 02:43
为什么要对AFNetworking进行多一层的封装
对于AFNetworking进行二次封装是很有必要的。事实上,在项目中大量使用第三方网络库是有风险的,因为网络请求的使用遍布整个应用,而一旦该对应的网络库不再更新维护,或者我们有意愿的去更换网络框架,修改将会有着巨大的难以承受的工作量。
这一个框架与其他框架有什么不同
本框架基于AFNetworking3.0的版本进行封装,面向更新的版本。
为网络请求的任务管理做了大量的工作,使得下载上传,或者其他使用环境下的任务管理得以更轻松的实现。
反其道而行,专为Post请求作出了缓存处理,这一部分缓存处理的使用与否,由使用者自行决定。
自定义Get请求的缓存策略,以时间为基准,严格把控缓存的有效性。
接口设计
请求
这里使用了新建NS_ENUM的方式来统一Post和Get接口。
/** * 请求方式 */typedef NS_ENUM(NSInteger, CBRequestType) { /** * POST方式来进行请求 */ CBPOSTRequest = 1 << 0, /** * GET方式来进行请求 */ CBGETRequest = 1 << 1};
/** * 统一请求接口 * * @param url 请求路径 * @param params 拼接参数 * @param httpMethod 请求方式(0为POST,1为GET) * @param useCache 是否使用缓存 * @param progressBlock 进度回调 * @param successBlock 成功回调block * @param failBlock 失败回调block * * @return 返回的对象中可取消请求 */+ (CBURLSessionTask *)requestWithUrl:(NSString *)url params:(NSDictionary *)params useCache:(BOOL)useCache httpMedthod:(CBRequestType)httpMethod progressBlock:(CBNetWorkingProgress)progressBlock successBlock:(CBResponseSuccessBlock)successBlock failBlock:(CBResponseFailBlock)failBlock;
从上面的代码我们可以看到,参数useCache决定着你是否使用Post请求的缓存功能,而即便将其设置为NO,依然会自动开启Get请求的缓存功能。
数据解析方式
/** * 数据串行方式 */typedef NS_ENUM(NSInteger, CBSerializerType) { /** * HTTP方式来进行请求或响应 */ CBHTTPSerializer = 1 << 0, /** * JSON方式来进行请求或响应 */ CBJSONSerializer = 1 << 1};
/** * 更新请求或者返回数据的解析方式(0为HTTP模式,1为JSON模式) * * @param requestType 请求数据解析方式 * @param responseType 返回数据解析方式 */+ (void)updateRequestSerializerType:(CBSerializerType)requestType responseSerializer:(CBSerializerType)responseType;
上面的NS_ENUM联合上面的方法可以更改数据解析方式,更具灵活性。
文件上传,下载
/** * 文件上传接口 * * @param url 传文件接口地址 * @param uploadingFile 上传文件路径 * @param progressBlock 上传进度 * @param successBlock 成功回调 * @param failBlock 失败回调 * * @return 返回的对象中可取消请求 */+ (CBURLSessionTask *)uploadFileWithUrl:(NSString *)url uploadingFile:(NSString *)uploadingFile progressBlock:(CBNetWorkingProgress)progressBlock successBlock:(CBResponseSuccessBlock)successBlock failBlock:(CBResponseFailBlock)failBlock;
/** * 文件下载接口 * * @param url 下载文件接口地址 * @param saveToPath 存储目录 * @param progressBlock 下载进度 * @param successBlock 成功回调 * @param failBlock 下载回调 * * @return 返回的对象可取消请求 */+ (CBURLSessionTask *)downloadWithUrl:(NSString *)url saveToPath:(NSString *)saveToPath progressBlock:(CBNetWorkingProgress)progressBlock successBlock:(CBResponseSuccessBlock)successBlock failBlock:(CBResponseFailBlock)failBlock;
针对文件的下载和上传的做出专门的设计。
任务管理
由上面的方法中,我们可以看到每一个方法都返回了一个任务对象CBURLSessionTask,这个对象继承于NSURLSessionTask,如此我们可以直接的取到每次进行任务请求的对象,直接对其进行管理。但不止于此,我仍然写了以下的几个接口来更快捷更集中的对其进行管理。
/** * 取消所有请求 */+ (void)cancelAllRequest;
/** * 根据url取消请求 * * @param url 请求url */+ (void)cancelRequestWithURL:(NSString *)url;
通过这两个方法,我们可以直接取消所有的请求,或者取消单个链接对应的请求。全局性的执行取消操作,更方便。
缓存处理
Post缓存处理
由于苹果官方的NSURLCache不支持Post请求的缓存处理,所有这一部分的缓存处理,我自己通过归档的方式来进行管理。
主要的方法如下:
+ (id)getCacheResponseWithURL:(NSString *)url params:(NSDictionary *)params { id cacheData = nil; if (url) { NSString *directoryPath = DIRECTORYPATH; NSString *originString = [NSString stringWithFormat:@"%@+%@",url,params]; NSString *path = [directoryPath stringByAppendingPathComponent:[self md5:originString]]; NSData *data = [[NSFileManager defaultManager] contentsAtPath:path]; if (data) { cacheData = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:nil]; } } return cacheData;}
+ (void)cacheResponseObject:(id)responseObject request:(NSURLRequest *)request params:(NSDictionary *)params { if (request && responseObject && ![responseObject isKindOfClass:[NSNull class]]) { NSString *directoryPath = DIRECTORYPATH; NSError *error = nil; if (![[NSFileManager defaultManager] fileExistsAtPath:directoryPath isDirectory:nil]) { [[NSFileManager defaultManager] createDirectoryAtPath:directoryPath withIntermediateDirectories:YES attributes:nil error:&error]; } NSString *originString = [NSString stringWithFormat:@"%@+%@",request.URL.absoluteString,params]; NSString *path = [directoryPath stringByAppendingPathComponent:[self md5:originString]]; NSDictionary *dict = (NSDictionary *)responseObject; NSData *data = nil; if ([dict isKindOfClass:[NSData class]]) { data = responseObject; } else { data = [NSJSONSerialization dataWithJSONObject:dict options:NSJSONWritingPrettyPrinted error:&error]; } if (data && error == nil) { [[NSFileManager defaultManager] createFileAtPath:path contents:data attributes:nil]; } }}+ (NSString *)md5:(NSString *)string { if (string == nil || [string length] == 0) { return nil; } unsigned char digest[CC_MD5_DIGEST_LENGTH], i; CC_MD5([string UTF8String], (int)[string lengthOfBytesUsingEncoding:NSUTF8StringEncoding], digest); NSMutableString *ms = [NSMutableString string]; for (i = 0; i < CC_MD5_DIGEST_LENGTH; i++) { [ms appendFormat:@"%02x", (int)(digest[i])]; } return [ms copy];}
值得注意的是,每一次进行缓存,都通过HASH的方式对缓存进行了加密,从而达到唯一缓存和更加安全的目的。
Get请求的自定义
按道理,官方已经对于Get请求进行了很完善的缓存处理,为什么我还要自行处理呢?事实上,我并没有自定义这一部分的处理,我仅对于NSURLCache加多了一层封装,从而达到自定义策略的目的,主要的方法如下所示:
- (id)cachedResponseForRequest:(NSURLRequest *)request { NSCachedURLResponse *cachedResponse = [super cachedResponseForRequest:request]; if (cachedResponse) { NSDate *cacheDate = cachedResponse.userInfo[CBURLCacheExpirationKey]; NSDate *cacheExpirationDate = [cacheDate dateByAddingTimeInterval:CBURLCacheExpirationInterval]; if ([cacheExpirationDate compare:[NSDate date]] == NSOrderedAscending) { [self removeCachedResponseForRequest:request]; return nil; } } id responseObj = [NSJSONSerialization JSONObjectWithData:cachedResponse.data options:NSJSONReadingAllowFragments error:nil]; return responseObj;}
- (void)storeCachedResponse:(id)response responseObjc:(id)responseObjc forRequest:(NSURLRequest *)request { NSData *data = [NSJSONSerialization dataWithJSONObject:responseObjc options:NSJSONWritingPrettyPrinted error:nil]; NSMutableDictionary *userInfo = [[NSMutableDictionary alloc] init]; userInfo[CBURLCacheExpirationKey] = [NSDate date]; NSCachedURLResponse *modifiedCachedResponse = [[NSCachedURLResponse alloc] initWithResponse:response data:data userInfo:userInfo storagePolicy:0]; [super storeCachedResponse:modifiedCachedResponse forRequest:request];}
小结
更详细的代码请大家点击下载查看,谢谢大家的关注,如果可以,请点个star支持一下,谢谢。
- CBNetworking:源码分析
- 源码分析
- 源码分析
- 源码分析
- 源码分析
- 源码分析
- 源码分析
- 源码分析
- 源码分析
- 源码分析:SparseArray分析
- 源码- Spark Broadcast源码分析
- Android源码/框架源码分析
- 【Android应用源码分析】HandlerThread 源码分析
- 【Android应用源码分析】IntentService 源码分析
- java源码分析01-Object源码分析
- VC++源码分析 - 中国象棋源码分析
- [Java源码分析]ArrayList源码分析
- [java源码分析]LinkedList源码分析
- Android 快速开发环境-Eclipse版(附完整资源)
- RPC和WebService的区别
- 所有的字母,所有的数字
- 通过关键代码段实现的一个互斥锁CLock
- 四种常见的POST提交数据方式
- CBNetworking:源码分析
- ubuntu 16.04LTS 下Code::Blocks 16.01 安装
- C/C++之回调函数
- 添加 module 到 python 的 path 中(自动找到module)
- 【2016-08-09】{[Csrf token],[Redis]}
- Android 消息机制:Handler、Looper、Message源码 详细版解析 ------从入门到升天
- 布局中样式抽取
- AFNetworking3.1 基本使用
- CBImagePicker:源码分析