diff --git a/README.md b/README.md index 27b7c06..8ae36e0 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ [![Cocoapods](https://img.shields.io/cocoapods/p/YBNetwork.svg)](https://github.com/indulgeIn/YBNetwork)  [![License](https://img.shields.io/github/license/indulgeIn/YBNetwork.svg)](https://github.com/indulgeIn/YBNetwork)  -基于 AFNetworking 二次封装,调用方便,设计简洁,易于拓展。 +基于 AFNetworking 二次封装,功能细致易拓展。 设计原理博客:[谈谈 iOS 网络层设计](https://www.jianshu.com/p/fe0dd50d0af1) @@ -16,6 +16,7 @@ - 支持缓存写入模式、读取模式、有效时长等自定义配置 (同时享有来着 YYCache 的优越性能) - 支持发起请求和响应回调的预处理 +- 支持网络落地异步重定向 - 重复请求处理策略选择 - 网络请求释放策略选择 - 支持 Block 和 Delegate 回调方式 @@ -24,11 +25,21 @@ ## 安装 +### CocoaPods + +1. 在 Podfile 中添加 `pod 'YBNetwork'`。 +2. 执行 `pod install` 或 `pod update`。 + +若搜索不到库,可使用 rm ~/Library/Caches/CocoaPods/search_index.json 移除本地索引然后再执行安装,或者更新一下 CocoaPods 版本。 + +### 手动导入 + 1. 下载 YBNetwork 文件夹所有内容并且拖入你的工程中。 2. 链接以下 frameworks: * AFNetworking * YYCache + ## 用法 可下载 DEMO 查看示例。 @@ -36,6 +47,7 @@ ### 基本使用 #### 1、第一步 + 创建子类继承自`YBBaseRequest`,并且在构造方法中初始化一些通用的配置 (比如服务器地址、解析器) ``` @interface DefaultServerRequest : YBBaseRequest @@ -46,17 +58,17 @@ self = [super init]; if (self) { self.baseURI = @"https://www.baidu.com"; - self.requestSerializer = [AFHTTPRequestSerializer serializer]; - self.requestSerializer.timeoutInterval = 30; - self.responseSerializer = [AFJSONResponseSerializer serializer]; } return self; } +- (AFHTTPRequestSerializer *)requestSerializer {...} +- (AFHTTPResponseSerializer *)responseSerializer {...} @end ``` 如果项目接口来自不同的接口团队(往往通用配置不同),那么就为每一个接口团队子类化一个`YBBaseRequest`,然后分别配置通用配置。 #### 2、第二步 + 创建具体接口配置,有两种方式,一种是直接实例化`DefaultServerRequest`,一种是继续子类化`DefaultServerRequest`: ``` //直接实例化 @@ -83,6 +95,7 @@ request.requestParameter = @{...}; ``` #### 3、第三步 + 发起网络请求,设置回调: ``` //Block @@ -104,7 +117,9 @@ request.delegate = self; //代理方法回调结果 注意:虽然 Block 方式就算不弱引用`self`也不会循环引用 (内部会回调完成后破除循环),但是为了避免延长`self`的生命周期,强烈建议使用弱引用,不然可能会导致网络请求释放策略失效。如果你是主导者,那么可以规定必须使用 Delegate 方式回调,从源头上避免延长网络响应接受者生命周期。 + ### 请求和响应预处理 + 往往我们需要为所有请求参数添加一些字段,比如设备ID,用户ID。 只需要在一级子类`DefaultServerRequest`中重载父类方法就行了: ``` @@ -124,16 +139,28 @@ request.delegate = self; //代理方法回调结果 - (void)yb_preprocessSuccessInMainThreadWithResponse:(YBNetworkResponse *)response { //预处理请求成功 } -- (void)yb_preprocessFailureInChildThreadWithResponse:(YBNetworkResponse *)response { - //预处理请求失败 -} -- (void)yb_preprocessFailureInMainThreadWithResponse:(YBNetworkResponse *)response { - //预处理请求失败 -} +... @end ``` +### 重定向 + +网络落地重定向使用此方法: +``` +- (void)yb_redirection:(void (^)(YBRequestRedirection))redirection response:(YBNetworkResponse *)response { + // 同步或异步的做一些事情 + redirection(YBRequestRedirectionSuccess); +} +``` +使用`redirection`闭包来达到可异步重定向的能力,在这之间可以做一些具体网络接口无感知的逻辑。 + + +### 为响应对象添加属性 + +`YBNetworkResponse` 包含必要的响应数据,可以添加额外属性,在网络响应预处理时为这些属性赋值,那么具体接口调用方就可以很方便的拿到这些处理后的值了。建议创建一个`YBNetworkResponse`的分类,使用 Runtime 的关联属性来拓展。 + + ### 缓存处理 缓存处理配置都在`request.cacheHandler`变量`YBNetworkCache`类中,支持以下配置: @@ -141,27 +168,28 @@ request.delegate = self; //代理方法回调结果 - 缓存命中后是否继续发起网络请求 - 缓存的有效时长 - 定制缓存的 key -- 根据请求响应成功数据判断是否需要缓存(比如仅当 code=0 时数据有效允许缓存) -- 以及直接配置 YYCache +- 直接配置 YYCache + +##### 缓存有效性验证 -缓存命中提供了 Block 和代理方法的回调,一定要根据业务合理选择缓存机制,谨慎使用。 +内部会在业务处理完成网络响应数据后尝试进行缓存,且提供一个`shouldCacheBlock`可根据请求响应成功数据判断是否需要缓存(比如仅当 `code == 0` 时数据有效允许缓存)。 ### 重复网络请求处理策略 `request.repeatStrategy`变量配置,三种策略: -1. 允许重复网络请求 -2. 取消最旧的网络请求 -3. 取消最新的网络请求 +- 允许重复网络请求 +- 取消最旧的网络请求 +- 取消最新的网络请求 举几个例子,当接口数据并不会在短时间变化时,重复发起网络请求就会浪费网络资源,可以选择方案 2 或 3;比如在搜索业务中,用户往往频繁的调用搜索接口,而发起一次搜索时,之前的搜索请求一般是没有意义了,就可以选用方案 2。 ### 网络请求释放策略 `request.releaseStrategy`变量配置,有几种方式可以选择: -1. 网络任务会持有 YBBaseRequest 实例,网络任务完成 YBBaseRequest 实例才会释放 -2. 网络请求将随着 YBBaseRequest 实例的释放而取消 -3. 网络请求和 YBBaseRequest 实例无关联 +- 网络任务会持有 YBBaseRequest 实例,网络任务完成 YBBaseRequest 实例才会释放 +- 网络请求将随着 YBBaseRequest 实例的释放而取消 +- 网络请求和 YBBaseRequest 实例无关联 举几个例子,若你的控制器出栈以后希望取消未落地的网络请求,那么就使用方案 2,注意管理好 YBBaseRequest 的生命周期就行了;若你的网络请求是不论如何都不希望它取消的,那么使用方案 3;若你希望网络请求任务始终持有 YBBaseRequest 实例避免它提前释放,那么使用方案 1。 diff --git a/YBNetwork.podspec b/YBNetwork.podspec index e9b84f6..fe96f94 100644 --- a/YBNetwork.podspec +++ b/YBNetwork.podspec @@ -4,7 +4,7 @@ Pod::Spec.new do |s| s.name = "YBNetwork" - s.version = "1.0.5" + s.version = "1.0.6" s.summary = "基于 AFNetworking 网络中间层,注重性能,设计简洁,易于拓展" s.description = <<-DESC 基于 AFNetworking 网络中间层,注重性能,设计简洁,易于拓展。 diff --git a/YBNetwork/YBBaseRequest.m b/YBNetwork/YBBaseRequest.m index da1b681..03cf517 100644 --- a/YBNetwork/YBBaseRequest.m +++ b/YBNetwork/YBBaseRequest.m @@ -136,7 +136,10 @@ - (void)clearRequestBlocks { #pragma mark - request - (void)startWithCacheKey:(NSString *)cacheKey { + __weak typeof(self) weakSelf = self; BOOL(^cancelled)(NSNumber *) = ^BOOL(NSNumber *taskID){ + __strong typeof(weakSelf) self = weakSelf; + if (!self) return YES; YBN_IDECORD_LOCK(BOOL contains = [self.taskIDRecord containsObject:taskID];) return !contains; }; @@ -229,13 +232,6 @@ - (void)requestCompletionWithResponse:(YBNetworkResponse *)response cacheKey:(NS } - (void)successWithResponse:(YBNetworkResponse *)response cacheKey:(NSString *)cacheKey fromCache:(BOOL)fromCache taskID:(NSNumber *)taskID { - - BOOL shouldCache = !self.cacheHandler.shouldCacheBlock || self.cacheHandler.shouldCacheBlock(response); - BOOL isSendFile = self.requestConstructingBody || self.downloadPath.length > 0; - if (!fromCache && !isSendFile && shouldCache) { - [self.cacheHandler setObject:response.responseObject forKey:cacheKey]; - } - if ([self respondsToSelector:@selector(yb_preprocessSuccessInChildThreadWithResponse:)]) { [self yb_preprocessSuccessInChildThreadWithResponse:response]; } @@ -260,6 +256,13 @@ - (void)successWithResponse:(YBNetworkResponse *)response cacheKey:(NSString *)c self.successBlock(response); } [self clearRequestBlocks]; + + // 在网络响应数据被业务处理完成后进行缓存,可避免将异常数据写入缓存(比如数据导致 Crash 的情况) + BOOL shouldCache = !self.cacheHandler.shouldCacheBlock || self.cacheHandler.shouldCacheBlock(response); + BOOL isSendFile = self.requestConstructingBody || self.downloadPath.length > 0; + if (!isSendFile && shouldCache) { + [self.cacheHandler setObject:response.responseObject forKey:cacheKey]; + } } if (taskID) [self.taskIDRecord removeObject:taskID]; diff --git a/YBNetworkDemo/TestCase/TestViewController.m b/YBNetworkDemo/TestCase/TestViewController.m index 35f4e6a..c773492 100644 --- a/YBNetworkDemo/TestCase/TestViewController.m +++ b/YBNetworkDemo/TestCase/TestViewController.m @@ -54,7 +54,7 @@ - (void)searchA { DefaultServerRequest *request = [DefaultServerRequest new]; request.cacheHandler.writeMode = YBNetworkCacheWriteModeMemoryAndDisk; - request.cacheHandler.readMode = YBNetworkCacheReadModeAlsoNetwork; + request.cacheHandler.readMode = YBNetworkCacheReadModeCancelNetwork; request.requestMethod = YBRequestMethodGET; request.requestURI = @"charconvert/change.from"; request.requestParameter = @{@"key":@"0e27c575047e83b407ff9e517cde9c76", @"type":@"2", @"text":@"呵呵呵呵"};