版本记录
版本号 | 时间 |
---|---|
V1.0 | 2018.02.28 |
前言
我们做APP发起网络请求,都离不开一个非常有用的框架AFNetworking,可以说这个框架的知名度已经超过了苹果的底层网络请求部分,很多人可能不知道苹果底层是如何发起网络请求的,但是一定知道
AFNetworking
,接下来几篇我们就一起详细的解析一下这个框架。感兴趣的可以看上面写的几篇。
1. AFNetworking源码探究(一) —— 基本介绍
2. AFNetworking源码探究(二) —— GET请求实现之NSURLSessionDataTask实例化(一)
3. AFNetworking源码探究(三) —— GET请求实现之任务进度设置和通知监听(一)
4. AFNetworking源码探究(四) —— GET请求实现之代理转发思想(一)
5. AFNetworking源码探究(五) —— AFURLSessionManager中NSURLSessionDelegate详细解析(一)
6. AFNetworking源码探究(六) —— AFURLSessionManager中NSURLSessionTaskDelegate详细解析(一)
回顾
上一篇主要介绍了NSURLSessionTaskDelegate
中五个代理方法的实现及其使用场景和注意事项。这一篇主要介绍NSURLSessionDataDelegate
几个代理方法。
1. - (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveResponse:(NSURLResponse *)response completionHandler:(void (^)(NSURLSessionResponseDisposition disposition))completionHandler;
首先看一下苹果该方法的API
/* The task has received a response and no further messages will be
* received until the completion block is called. The disposition
* allows you to cancel a request or to turn a data task into a
* download task. This delegate message is optional - if you do not
* implement it, you can get the response as a property of the task.
*
* This method will not be called for background upload tasks (which cannot be converted to download tasks).
*/
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask
didReceiveResponse:(NSURLResponse *)response
completionHandler:(void (^)(NSURLSessionResponseDisposition disposition))completionHandler;
看一下AFN中该方法的实现
- (void)URLSession:(NSURLSession *)session
dataTask:(NSURLSessionDataTask *)dataTask
didReceiveResponse:(NSURLResponse *)response
completionHandler:(void (^)(NSURLSessionResponseDisposition disposition))completionHandler
{
NSURLSessionResponseDisposition disposition = NSURLSessionResponseAllow;
if (self.dataTaskDidReceiveResponse) {
disposition = self.dataTaskDidReceiveResponse(session, dataTask, response);
}
if (completionHandler) {
completionHandler(disposition);
}
}
这里,NSURLSessionResponseDisposition disposition = NSURLSessionResponseAllow;
表示默认为继续进行。
-
completionHandler
这个block,通过传入一个类型为NSURLSessionResponseDisposition
的变量来决定该传输任务接下来该做什么:-
NSURLSessionResponseAllow
该task正常进行 -
NSURLSessionResponseCancel
该task会被取消 -
NSURLSessionResponseBecomeDownload
会调用URLSession:dataTask:didBecomeDownloadTask:
方法来新建一个download task
以代替当前的data task
-
NSURLSessionResponseBecomeStream
转成一个StreamTask
-
当你把添加
content-type
的类型为multipart/x-mixed-replace
那么服务器的数据会分片的传回来。然后这个方法是每次接受到对应片响应的时候会调被调用。你应该在这个函数中合理地处理先前的数据,否则会被新数据覆盖。
2. - (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didBecomeDownloadTask:(NSURLSessionDownloadTask *)downloadTask;
首先看一下苹果该方法的API
/* Notification that a data task has become a download task. No
* future messages will be sent to the data task.
*/
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask
didBecomeDownloadTask:(NSURLSessionDownloadTask *)downloadTask;
看一下AFN中该方法的实现
- (void)URLSession:(NSURLSession *)session
dataTask:(NSURLSessionDataTask *)dataTask
didBecomeDownloadTask:(NSURLSessionDownloadTask *)downloadTask
{
AFURLSessionManagerTaskDelegate *delegate = [self delegateForTask:dataTask];
if (delegate) {
[self removeDelegateForTask:dataTask];
[self setDelegate:delegate forTask:downloadTask];
}
if (self.dataTaskDidBecomeDownloadTask) {
self.dataTaskDidBecomeDownloadTask(session, dataTask, downloadTask);
}
}
当代理1方法中的disposition = NSURLSessionResponseBecomeDownload
的时候,就会调用这个方法。
这个代理方法是被上面的代理方法触发的,作用就是新建一个downloadTask
,替换掉当前的dataTask
。所以我们在这里做了AF自定义代理的重新绑定操作[self setDelegate:delegate forTask:downloadTask];
。
3. - (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data
首先看一下苹果该方法的API
/* Sent when data is available for the delegate to consume. It is
* assumed that the delegate will retain and not copy the data. As
* the data may be discontiguous, you should use
* [NSData enumerateByteRangesUsingBlock:] to access it.
*/
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask
didReceiveData:(NSData *)data;
看一下AFN中该方法的实现
- (void)URLSession:(NSURLSession *)session
dataTask:(NSURLSessionDataTask *)dataTask
didReceiveData:(NSData *)data
{
AFURLSessionManagerTaskDelegate *delegate = [self delegateForTask:dataTask];
[delegate URLSession:session dataTask:dataTask didReceiveData:data];
if (self.dataTaskDidReceiveData) {
self.dataTaskDidReceiveData(session, dataTask, data);
}
}
- 获取到数据就会调用,会被反复调用,请求到的数据就在这被拼装完整。
- 这个方法和上面
didCompleteWithError
算是NSURLSession
的代理中最重要的两个方法。 - 我们转发了这个方法到AF的代理中去,所以数据的拼接都是在AF的代理中进行的。这也是情理中的,毕竟每个响应数据都是对应各个task,各个AF代理的。在
AFURLSessionManager
都只是做一些公共的处理。
4. - (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask willCacheResponse:(NSCachedURLResponse *)proposedResponse completionHandler:(void (^)(NSCachedURLResponse * _Nullable cachedResponse))completionHandler;
首先看一下苹果该方法的API
/* Invoke the completion routine with a valid NSCachedURLResponse to
* allow the resulting data to be cached, or pass nil to prevent
* caching. Note that there is no guarantee that caching will be
* attempted for a given resource, and you should not rely on this
* message to receive the resource data.
*/
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask
willCacheResponse:(NSCachedURLResponse *)proposedResponse
completionHandler:(void (^)(NSCachedURLResponse * _Nullable cachedResponse))completionHandler;
看一下AFN中该方法的实现
- (void)URLSession:(NSURLSession *)session
dataTask:(NSURLSessionDataTask *)dataTask
willCacheResponse:(NSCachedURLResponse *)proposedResponse
completionHandler:(void (^)(NSCachedURLResponse *cachedResponse))completionHandler
{
NSCachedURLResponse *cachedResponse = proposedResponse;
if (self.dataTaskWillCacheResponse) {
cachedResponse = self.dataTaskWillCacheResponse(session, dataTask, proposedResponse);
}
if (completionHandler) {
completionHandler(cachedResponse);
}
}
- 该方法的作用就是询问data task或上传任务(upload task)是否缓存response。
- 当task接收到所有期望的数据后,session会调用此代理方法。
- 当task接收到所有期望的数据后,session会调用此代理方法。如果你没有实现该方法,那么就会使用创建session时使用的configuration对象决定缓存策略。这个代理方法最初的目的是为了阻止缓存特定的URLs或者修改
NSCacheURLResponse
对象相关的userInfo
字典。 - 该方法只会当
request
决定缓存response
时候调用。作为准则,responses只会当以下条件都成立的时候返回缓存:- 该request是HTTP或HTTPS URL的请求(或者你自定义的网络协议,并且确保该协议支持缓存)
- 确保request请求是成功的(返回的status code为200-299)
- 返回的response是来自服务器端的,而非缓存中本身就有的
- 提供的
NSURLRequest
对象的缓存策略要允许进行缓存 - 服务器返回的response中与缓存相关的header要允许缓存
- 该response的大小不能比提供的缓存空间大太多(比如你提供了一个磁盘缓存,那么response大小一定不能比磁盘缓存空间还要大5%)
后记
本篇主要介绍了NSURLSessionDataDelegate中四个代理方法的实现及其使用场景和注意事项。