网络层方法封装3.1
** 其实很久之前就想写写这个东西,不过因为项目的原因一直没时间去整理出来,所以决定还是分开几天去写完这个东西吧
新增特性:
- 3.0
- 多缓存策略
- 用宏定义减少代码量
- 使用 plist统一错误信息设置
- 3.1
先讲讲本地持久化策略的选择
缓存策略
1 2 3 4 5 6 7 8
| typedef NS_ENUM(NSInteger,DKCacheStrategy){ DKCacheStrategy_CACHE_ONLY, // 只从本地取数据 DKCacheStrategy_NETWORK_ONLY, // 只从网络取数据(不缓存) DKCacheStrategy_NETWORK_AND_CACHE, // 从网络取数据后缓存(缓存结束不回调) DKCacheStrategy_CACHE_ELSE_NETWORK, // 先取缓存,如果没有数据的话,才从网络取数据 DKCacheStrategy_CACHE_THEN_NETWORK // 先取缓存,再加载网络数据,网络数据加载完会更新缓存,这个选择会有两次回调 DKCacheStrategy_AUTOMATIC // 根据当前网络环境自动选择,如果有网络(WIFI/WLAN)就取网络数据,没网络就取缓存数据 };
|
- Demo 说明
- github地址:没有
- 下载地址: NetworkDemo
- 选择本地持久化方式:
YYCache
,如果有更适合的缓存机制,那改一改也挺简单
- 方法接口设计
1 2 3 4 5 6 7 8 9 10 11 12
| /** * 发送HTTP请求 * * @param method 请求方法,你可以写@"get"或者@"post"(不区分大小写)或者已经定义好的 kGET 或 kPOST * @param strategy 缓存策略 * @param header 请求头,可为空 * @param params 请求参数,可为空 * @param block 返回回调,这个就不要空啦 * * @return 请求标示 id 可以用来取消请求 */ - (NSInteger)requestForMethod:(NSString *)method cacheStragety:(DKCacheStrategy)strategy url:(NSString *)URLString header:(NSDictionary *)header params:(NSDictionary *)params responseBlock:(DKHTTPResponseBlock)block;
|
之前两个方法继续保留,在这里就不说明了
1 2
| - (void)cancelAllRequest; - (void)cancelRequestWithRequestIds:(NSArray *)requestIds;
|
然后写两个内部方法,分别是取缓存和取网络数据
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| #pragma mark - 仅本地 - (NSInteger)requestWithCacheOnlyStrategyWithUrl:(NSString *)URLString params:(NSDictionary *)params requestBlock:(DKHTTPResponseBlock)block { DKResponse *response = (DKResponse *)[self.cache objectForKey:[self cacheKeyForRequestUrl:URLString params:params]]; if (block) { if (response) { block(response); }else{ block(KERROR_RESPONSE(-1)); } } return 0; }
#pragma mark - 仅网络 - (NSInteger)requestWithNetworkOnlyStrategyForMethod:(NSString *)method url:(NSString *)URLString header:(NSDictionary *)header params:(NSDictionary *)params responseBlock:(DKHTTPResponseBlock)block { NSNumber *taskIdentifier = 0; if ([method.uppercaseString isEqualToString:@"GET"]) { DKCALLAPI(GET, taskIdentifier); }else if([method.uppercaseString isEqualToString:@"POST"]){ DKCALLAPI(POST, taskIdentifier); }else{ return 0; } return taskIdentifier.integerValue; }
|
这里的宏DKCALLAPI 定义 主要是为了不想写 POST和 GET两个方法,在这里写一次就够了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| #define DKCALLAPI(REQUEST_METHOD,REQUEST_ID) \ {\ AFHTTPSessionManager *mgr = [AFHTTPSessionManager manager];\ AFHTTPRequestSerializer *requestSerializer = mgr.requestSerializer;\ if (header) {\ [header enumerateKeysAndObjectsUsingBlock:^(id _Nonnull key, id obj, BOOL * _Nonnull stop) {\ [requestSerializer setValue:obj forHTTPHeaderField:key];\ }];\ }\ requestSerializer.timeoutInterval = kTimeOutInterval;\ NSURLSessionTask *task = [mgr REQUEST_METHOD:URLString parameters:params progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {\ DKResponse *resp = [DKResponse mj_objectWithKeyValues:responseObject];\ resp.rawData = responseObject;\ resp.taskIdentifier = task.taskIdentifier;\ if(block){\ block(resp);\ }\ } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {\ DKResponse *resp = [DKResponse responseWithErrorOnly:error.description code:error.code];\ if (block) {\ block(resp);\ }\ }];\ REQUEST_ID = @(task.taskIdentifier);\ [self.dispatchTable setObject:task forKey:REQUEST_ID];\ }
|
然后 就可以实现我们的接口了 switch 里面的东西就就根据注释写吧
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| - (NSInteger)requestForMethod:(NSString *)method cacheStragety:(DKCacheStrategy)strategy url:(NSString *)URLString header:(NSDictionary *)header params:(NSDictionary *)params responseBlock:(DKHTTPResponseBlock)block { __weak typeof(self) weakSelf = self; NSInteger requestId; switch (strategy) { case DKCacheStrategy_CACHE_ONLY: // 调用获取缓存方法 break; case DKCacheStrategy_NETWORK_ONLY: // 调用获取网络方法 break; case DKCacheStrategy_NETWORK_AND_CACHE: // 调用网络方法,回调后写入本地缓存 break; case DKCacheStrategy_CACHE_ELSE_NETWORK: // 调用本地缓存方法,在回调中判断是否有缓存,如果没有的话调用网络方法 break; case DKCacheStrategy_CACHE_THEN_NETWORK: // 调用本地方法接着调用网络方法 break; case DKCacheStrategy_AUTOMATICALLY: // 调用网络方法,回调中如果返回错误则调用本地缓存方法 break; default: break; } return requestId; }
|
统一错误表处理
-建立一个plist 文件
1 2 3 4 5 6 7 8 9 10
| <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>-2</key> <string>网络连接失败</string> <key>-1</key> <string>没有缓存</string> </dict> </plist>
|
一个成员属性加一个方法去调用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| - (NSDictionary *)errorDic { if (!_errorDic) { NSString *path = [[NSBundle mainBundle] pathForResource:@"DKError" ofType:@"plist"]; _errorDic = [NSDictionary dictionaryWithContentsOfFile:path]; } return _errorDic; }
- (NSString *)errorDescriptionWithCode:(NSInteger)code { NSString *codeStr = [NSString stringWithFormat:@"%zd",code]; if ([self.errorDic.allKeys containsObject:codeStr]) { return self.errorDic[codeStr]; }else{ NSLog(@"没有定义该类型错误"); return nil; } }
|
包装成宏方便调用
1
| #define KERROR_RESPONSE(errCode) [DKResponse responseWithErrorOnly:[self errorDescriptionWithCode:errCode] code:errCode]
|
3.1 输出一个漂亮的 Log
1 2 3 4 5 6 7 8 9 10
| /** * 打印一个漂亮的 log * * @param method 请求方法 * @param url 接口地址 * @param params 参数 * @param response 响应对象 * @param showRequestContent 是否显示响应数据 */ + (void)logDebugInfoWithMethod:(NSString *)method URL:(NSString *)url params:(NSDictionary *)params response:(DKResponse *)response showRequestContent:(BOOL)showRequestContent;
|
里面主要是字符串拼接.要看详细的话就去下载 Demo吧!