YTKNetwork 源码解读 (一) 之 YTKBaseRequest
因为 YTKBaseRequest .h/.m 里代码数目不多,所以这里将从头开始逐行介绍,有一些直接就写在注释里了,有一些需要注意的地方会特别摘出来讲解的。
不知道你有没有注意到 NS_ENUM
后面没有跟着指定一个名字,是的,如果你不需要指定一个类型名字的话,可以直接这样子写。YTKRequestValidationErrorInvalidStatusCode
值的是 reponse.statusCode
不在 200~299 这个区间内,跟 AFHTTPResponseSerializer 的 acceptableStatusCodes
的范围一致
常见的请求方法
请求的序列化样式,相对于 AFNetworking 少了 AFPropertyListRequestSerializer,可能是因为这种编码方式比较少见吧。
相应的序列化样式,相对于 AFNetworking 少了 AFXMLDocumentResponseSerializer,AFPropertyListResponseSerializer,AFImageResponseSerializer,AFCompoundResponseSerializer 几个类型
对应于 NSURLSessionTask 的 priority 属性,需要在 iOS8 以后的系统中使用,不过一般也不需要再兼容之前的系统了吧。。。
AFMultipartFormData 在 AFNetworking 用于 Content-Type
为 application/form-data
的请求,将数据添加到请求体中。一般用于 upload task 中。
在 AFConstructingBlock 类型的 block 中,你可以将数据添加数据添加到请求体中
在 AFURLSessionTaskProgressBlock 的 block 你可以追踪上传的进度
你可以实现这两个协议,以便在 request 的不同阶段进行相应的处理
需要注意的是这些方法的执行顺序不要搞错了
接下来介绍 YTKBaseRequest
这个类,它是一个抽象类,提供了构建 requeset 时的许多选项
这里大部分的属性是映射 NSHTTPURLResponse
, NSURLRequest
,NSURLSessionTask
这几个类的属性的。
需要注意的是 responseObject
,如果 resumableDownloadPath
不为空并且 requestTask 是 DownloadTask 类型的,那么这个属性的值就一个文件路径(NSURL),用来保存下载数据的
tag 可以用来标记 YTKBaseRequest,默认值是 0
userInfo 可以用来添加额外信息
requestAccessories 是一个数组,可以用来保存多个
实现了 YTKRequestAccessory
协议的对象
constructingBodyBlock 用来将数据添加到请求体中
resumableDownloadPath 是保存下载数据文件的路径,当下载请求失败时,部分的下载数据会自动保存到这个文件中,否则数据会保存到 responseData/responseString 中
resumableDownloadProgressBlock 可以用来追踪下载进度
uploadProgressBlock 可以用来追踪上传进度
-setCompletionBlockWithSuccess:failure:
用来添加请求 成功/失败 的回调-clearCompletionBlock:
将请求 成功/失败 的回调 block 置为 nil,避免循环引用-addAccessory:
用来添加实现 YTKRequestAccessory 的对象
- -start:开启任务。需要注意是为了让 task 在完成之前不被释放掉,会在这个 task 添加到单例 YTKNetworkAgent 的成员变量
_requestsRecord
中 - -stop:取消任务。我感觉这个方法叫做 cancle 比较合适,我一开始看到 stop 还以为是 suspend 的意思
- -startWithCompletionBlockWithSuccess:failure:,设置请求 失败/成功 的回调,并开启任务
这部分是你实现 YTKBaseRequest 子类时可以覆写的方法
-requestCompletePreprocessor,-requestCompleteFilter,-requestFailedPreprocessor,-requestFailedFilter:这几个方法都是对请求 成功/失败 结果的处理,结合之前讲过 YTKRequestDelegate
,YTKRequestAccessory
两个协议里面的方法,下面给出这些方法的执行顺序.
请求成功后回调的执行顺序:
- requestCompletePreprocessor:如果使用 cache 的话是在主线程,否则的话在其它线程执行。下面的方法均在主线程执行
- requestWillStop
- requestCompleteFilter
- requestFinished
- successCompletionBlock
- requestDidStop
请求失败后回调的执行顺序
- requestFailedPreprocessor:如果使用 cache 的话是在主线程,否则的话在其它线程执行。下面的方法均在主线程执行
- requestWillStop
- requestFailedFilter
- requestFailed
- failureCompletionBlock
- requestDidStop
方法 -cacheFileNameFilterForRequestArgument
用来对请求参数 argument 进行过滤后返回一个新的参数,用在获取缓存文件名字上。
方法 -requestAuthorizationHeaderFieldArray
,用于身份验证,在这个方法中你需要返回一个容量为 2 的数组,第一个元素表示账号,第二个元素表示密码。
该认证方式使用用户的 账号/密码 作为凭证信息,进行 base64 编码添加到请求头 Authorization
中传输到服务器中
方法 buildCustomUrlRequest
,在这个方法里面你可以放回一个自定义的 request,而不是使用 AFNetworking 的 AFHTTPRequestSerializer 生成。
如果你返回了一个不为 nil 的对象,那么将忽略 requestUrl
, requestTimeoutInterval
, requestArgument
, allowsCellularAccess
, requestMethod
and requestSerializerType
方法 jsonValidator
,在这个方法里面,你可以对 reponse 序列化后的 JSON 对象进行验证。
举个例子,我们要向网址 http://www.yuantiku.com/iphone/users 发送一个 GET 请求,请求参数是 userId 。我们想获得某一个用户的信息,包括他的昵称和等级,我们需要服务器必须返回昵称(字符串类型)和等级信息(数值类型),则可以覆盖 jsonValidator 方法,实现简单的验证。
1 | - (id)jsonValidator { |
方法 statusCodeValidator
,我觉得如果是验证状态码的话好得加个状态码的参数啊,不过无所谓啦,反正可以自己获取状态码然后再进行判断。该方法返回一个布尔值,如果返回的是 NO 的话将会报错。
接下来讲 .m 文件
在 .h 文件中这些属性都是只读的,在 .m 文件中改成可读写,防止外部修改这些属性的值。
将 NSURLSessionTask
,NSURLResponse
的一些属性映射成自己的属性,便于使用
设置请求 成功/失败 的回调
需要注意的是可以添加多个实现了 YTKRequestAccessory 协议的对象
开启/关闭 请求的方法。
在 start 方法中:
1 | // 触发 YTKRequestAccessory 代理 |
在成功创建 task 后,task 将会被添加到 _requestsRecord 属性中避免被释放。随后调用 resume 开启任务
如果我们没有覆写方法 buildCustomUrlRequest 返回自定义的 request,系统会根据 YTKBaseRequest 创建 request。这部分在 sessionTaskForRequest:error:
中实现
获取 YTKBaseRequest 实例上各种属性的值,例如方法类型,参数,然后在根据 method 的不同,使用不同的方法创建 task。
因为这部分内容都在 YTKNetworkAgent,这里就简单提下。在后面讲解 YTKNetworkAgent 部分的时候再仔细说
在 stop
方法:
1 | // 执行代理 |
如果你的请求是下载任务,并且你指定了一个缓存文件名,那么下载好的部分数据将会写入这个临时文件中,在下次恢复下载时使用。
当然如果要使用断点下载,还需要满足下面的几个条件:
- 这个资源自你第一次请求后没有改变
- 这个任务是一个 HTTP 或者 HTTP GET 请求
- 服务器在 reponse header 提供了 ETag 或者 Last-Modified 字段
- 服务器支持字节范围请求
- 本地临时文件没有被删除
由于 YTKBaseRequest 是一个基类,所以在这些需要子类覆写的方法里面内容不多
覆写了 -description 方法,方便打印信息
YTKNetwork 源码解读 (一) 之 YTKBaseRequest
http://example.com/2020/07/13/YTKNetwork-源码解读-一-之-YTKBaseRequest/