AFNetWorking源码之NSURLSession系列概述

Posted by 黄成都 on 2017-04-14
Words 3.5k and Reading Time 15 Minutes
Viewed Times

1 基本说明

记得我刚做iOS的时候,那时候还是ASI和AFN共存,甚至ASI使用比例还多点,一转眼几年过去,ASI基本已经消失了,AFN基本成了iOS项目的标配。我虽然以前也有看过AFN2.x的源码,但是对于AFN3.x的源码一直没有自己阅读。接下来我会对AFN3.x学习并且写博客记录。得益于NSURLSession的强大功能,ANF3.0放弃了NSURLConnection这一部分,让代码简化了很多,但是功能却更加丰富。我觉得在学习AFN之前,有必要仔细了解NSURLSessionhttps相关,不然会有很多地方迷惑不解,具体可以看我的git仓库iOSSourceCodeStudy 。同时我强烈推荐浏览一下NSURLSession.h这个文件。

2 相互关系

我们首先来看一下一个简单的NSURLSession请求代码:

1
2
3
4
5
6
NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:[[NSOperationQueue alloc] init]];

NSURLRequest *request = [[NSURLRequest alloc]initWithURL:[NSURL URLWithString:bigPic]];

NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request];
[dataTask resume];

从上面我们发现,我们要发送一个网络请求,需要新建一个NSURLSession,新建一个NSURLSession又需要一个NSURLSessionConfiguration,并且还需要一些代理方法。同时我们需要一个NSURLSessionDataTask。所以说,我们的NSRULSession
网络请求系统包括一个session、一个configuration、一个Task已经Task附带的delegate。

  • 一个NSURLSession,总共只有一个类,也是最核心的类,他有一个对应的代理NSURLSessionDelegate
  • 一个NSURLSessionConfiguration,总共有三种模式。
  • 一个NSURLSessionTaskNSURLSessionTask是抽闲类,对应的代理NSURLSessionTaskDelegate。我们具体使用的时候,会使用他的三种子类,而且每个子类都有对应的delegate。

3 一个NSURLSession

首先我们看一下NSRULSession.h里面关于NSURLSession的部分。我们把它分为初始化部分、属性部分、dataTask部分、uploadTask部分、downloadTask部分。也就是说其他很多类都是围绕着下面这几个api衍生的。后面我们会每个部分分析。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
//初始化部分
@property (class, readonly, strong) NSURLSession *sharedSession;
+ (NSURLSession *)sessionWithConfiguration:(NSURLSessionConfiguration *)configuration;
+ (NSURLSession *)sessionWithConfiguration:(NSURLSessionConfiguration *)configuration delegate:(nullable id <NSURLSessionDelegate>)delegate delegateQueue:(nullable NSOperationQueue *)queue;

//属性部分
@property (readonly, retain) NSOperationQueue *delegateQueue;
@property (nullable, readonly, retain) id <NSURLSessionDelegate> delegate;
@property (readonly, copy) NSURLSessionConfiguration *configuration;

//dataTask部分
- (NSURLSessionDataTask *)dataTaskWithRequest:(NSURLRequest *)request;
- (NSURLSessionDataTask *)dataTaskWithURL:(NSURL *)url;

//uploadTask部分
- (NSURLSessionUploadTask *)uploadTaskWithRequest:(NSURLRequest *)request fromFile:(NSURL *)fileURL;
- (NSURLSessionUploadTask *)uploadTaskWithRequest:(NSURLRequest *)request fromData:(NSData *)bodyData;
- (NSURLSessionUploadTask *)uploadTaskWithStreamedRequest:(NSURLRequest *)request;

//downloadTask部分
- (NSURLSessionDownloadTask *)downloadTaskWithRequest:(NSURLRequest *)request;
- (NSURLSessionDownloadTask *)downloadTaskWithURL:(NSURL *)url;
- (NSURLSessionDownloadTask *)downloadTaskWithResumeData:(NSData *)resumeData;

3.1 Block的NSURLSession的api

我们都知道,NSRULConnection除了一套使用代理的API,还有一套对应的使用Block的api。NSURLSession也不列外。使用这一套api就不用实现代理方法。和delegate一样,Block也有dataTask系列、downloadTask系列、uploadTask系列。具体看下面:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
//dataTask系列
- (NSURLSessionDataTask *)dataTaskWithRequest:(NSURLRequest *)request completionHandler:(void (^)(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error))completionHandler{

}
- (NSURLSessionDataTask *)dataTaskWithURL:(NSURL *)url completionHandler:(void (^)(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error))completionHandler{

}
//unloadTast系列
- (NSURLSessionUploadTask *)uploadTaskWithRequest:(NSURLRequest *)request fromFile:(NSURL *)fileURL completionHandler:(void (^)(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error))completionHandler{

}
- (NSURLSessionUploadTask *)uploadTaskWithRequest:(NSURLRequest *)request fromData:(nullable NSData *)bodyData completionHandler:(void (^)(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error))completionHandler{

}
//downloadTask系列
- (NSURLSessionDownloadTask *)downloadTaskWithRequest:(NSURLRequest *)request completionHandler:(void (^)(NSURL * _Nullable location, NSURLResponse * _Nullable response, NSError * _Nullable error))completionHandler{

}
- (NSURLSessionDownloadTask *)downloadTaskWithURL:(NSURL *)url completionHandler:(void (^)(NSURL * _Nullable location, NSURLResponse * _Nullable response, NSError * _Nullable error))completionHandler{

}
- (NSURLSessionDownloadTask *)downloadTaskWithResumeData:(NSData *)resumeData completionHandler:(void (^)(NSURL * _Nullable location, NSURLResponse * _Nullable response, NSError * _Nullable error))completionHandler{

}

3.2 Block的NSURLSession使用

用dataTask下载一张图片,然后用imageView显示。

1
2
3
4
5
6
7
8
9
10
-(IBAction)requestBlockTaskTest:(id)sender{
[self clear];
NSURLSession *session = [NSURLSession sharedSession];
NSURLRequest *request = [[NSURLRequest alloc]initWithURL:[NSURL URLWithString:bigPic]];
NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
UIImage *image = [[UIImage alloc]initWithData:data];
self.imageView.image = image;
}];
[dataTask resume];
}

4 一个NSURLSessionConfiguration

首先看一下NSURLSessionConfiguration部分。从这个名字,我们可以预感到这个是与session的配置相关的,的确也是这样。总共有三种类型的configuratin,另外还有很多属性,比如配置缓存策略的requestCachePolicy,请求超时的timeoutIntervalForRequest,添加额外请求头的HTTPAdditionalHeaders,其他还有很多属性这里就不一一说了,具体看源码:

1
2
3
4
5
6
7
8
9
10
//默认的配置会将缓存存储在磁盘上
@property (class, readonly, strong) NSURLSessionConfiguration *defaultSessionConfiguration;
//第二种瞬时会话模式不会创建持久性存储的缓存.
@property (class, readonly, strong) NSURLSessionConfiguration *ephemeralSessionConfiguration;
//第三种后台会话模式允许程序在后台进行上传下载工作
+ (NSURLSessionConfiguration *)backgroundSessionConfigurationWithIdentifier:(NSString *)identifier;
//各种属性
@property NSURLRequestCachePolicy requestCachePolicy;
@property NSTimeInterval timeoutIntervalForRequest;
@property (nullable, copy) NSDictionary *HTTPAdditionalHeaders;

5 一个NSURLSessionTask

从上面NSURLSession初始化一个请求的时候,我们发现NSURLSessionTask并不能直接使用,只能使用他的子类。具体如下:

  • NSURLSessionTask抽象类。有对应的代理NSURLSessionTaskDelegate,而且这个代理继承了NSURLSessionDelegate代理。
  • NSURLSessionDataTaskNSURLSessionTask的子类。有对应的代理NSURLSessionTaskDelegate,而且这个代理继承了NSURLSessionTaskDelegate代理。我们一般网络请求,就用这个类。
  • NSURLSessionDownloadTaskNSURLSessionTask的子类。有对应的代理NSURLSessionDownloadDelegate,而且这个代理继承了NSURLSessionTaskDelegate代理。这个主要用于下载大文件等。
  • NSURLSessionUploadTaskNSURLSessionDataTask的子类。有对应的代理及时父类代理NSURLSessionDownloadDelegate。这个主要用于处理上传请求如上传图片。

从上面我们发现Task和delegate有一套对应的继承关系:

  • NSURLSessionTask (抽象类,NSURLSessionTaskDelegate)

    • NSURLSessionDataTask (NSURLSessionDataDelegate)
      • NSURLSessionUploadTask (NSURLSessionDataDelegate)
    • NSURLSessionDownloadTask (NSURLSessionDownloadDelegate)
  • NSURLSessionDelegate

    • NSURLSessionTaskDelegate
      • NSURLSessionDataDelegate
      • NSURLSessionDownloadDelegate

从继承关系上,我们就可以理解在初始化的时候,只通过设置NSURLSession对象的delegate就可以了。因为根据不同的task,其实就是设置了不同的delegate。这个设计避免了多次设置delegate的情况,同时也根据不同的task实现不同的delegate方法。真是一个很绝妙的设计。

6 代理说明

6.1 NSURLSessionDelegate

接下来我们看看NSURLSession的delegate对象NSURLSessionDelegate的方法,当一个session遇到错误、或者需要认证、应用进入后台都会调用下面的代理方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
//当一个session遇到系统错误或者未检测到的错误的时候,就会调用这个方法。
- (void)URLSession:(NSURLSession *)session didBecomeInvalidWithError:(nullable NSError *)error{

}
//当请求需要认证、或者https证书认证的时候,我们就需要在这个方法里面处理。
- (void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge
completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential * _Nullable credential))completionHandler{

}
//如果应用进入后台、这个方法会被调用。我们在这里可以对session发起的请求做各种操作比如请求完成的回调等。
- (void)URLSessionDidFinishEventsForBackgroundURLSession:(NSURLSession *)session {

}

6.2 NSURLSessionTaskDelegate

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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
/*
当请求重定向的时候调用这个方法。我们必须设置一个新的`NSURLRequest`对象传入completionHandler来重定向新的请求,但是当`session`是background模式的时候,这个方法不会被调用。
*/
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task
willPerformHTTPRedirection:(NSHTTPURLResponse *)response
newRequest:(NSURLRequest *)request
completionHandler:(void (^)(NSURLRequest * _Nullable))completionHandler{

}
/*
当请求需要认证的时候调用这个方法。如果没有实现这个代理,那么请求认证这个过程不会被调用。
*/
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task
didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge
completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential * _Nullable credential))completionHandler{

}
/*
如果请求需要一个新的请求体时,这个方法就会被调用。比如认证失败的时候,我们可以通过这个机会从新认证。
*/
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task
needNewBodyStream:(void (^)(NSInputStream * _Nullable bodyStream))completionHandler{

}
/*
当我们上传数据的时候,我们可以通过这个代理方法获取上传进度。
*/
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task
didSendBodyData:(int64_t)bytesSent
totalBytesSent:(int64_t)totalBytesSent
totalBytesExpectedToSend:(int64_t)totalBytesExpectedToSend{

}
/*
当task的统计信息收集好了以后,调用这个方法。
*/
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didFinishCollectingMetrics:(NSURLSessionTaskMetrics *)metrics {

}
/*
当一个task出错的时候,会调用这个方法。如果error是nil,也会调用这个方法,表示task完成。
*/
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task
didCompleteWithError:(nullable NSError *)error{
NSLog(@"数据返回以后,不管有错没错都回调用,如果没错,error及时nil");
}

6.3 NSURLSessionDataDelegate

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
29
30
31
32
33
34
35
36
37
38
/*
当一个task接收到返回信息。当所有信息都接收完毕以后,completionHandler会被调用。我们可以在这里取消一个网络请求或者把一个datatask转换为downloadtask。如果没有实现这个代理方法,我们也可以通过task的response属性获取到对应的数据。background模式的uploadtask不会调用这个方法。
*/
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask
didReceiveResponse:(NSURLResponse *)response
completionHandler:(void (^)(NSURLSessionResponseDisposition disposition))completionHandler{

}
/*
当一个datatask转换为一个downloadtask以后会调用。
*/
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask
didBecomeDownloadTask:(NSURLSessionDownloadTask *)downloadTask{
// 允许处理服务器的响应,才会继续接收服务器返回的数据
completionHandler(NSURLSessionResponseAllow);
}
/*
暂时忽略,这个是和数据流相关的。不管了
*/
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask
didBecomeStreamTask:(NSURLSessionStreamTask *)streamTask{

}
/*
当data可以使用的时候,调用这个方法。我们可以在这里获取data。
*/
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask
didReceiveData:(NSData *)data{

}
/*
允许我们在这里调用completionHandler缓存data,或者传入nil来禁止缓存
*/
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask
willCacheResponse:(NSCachedURLResponse *)proposedResponse
completionHandler:(void (^)(NSCachedURLResponse * _Nullable cachedResponse))completionHandler{

}

6.4 NSURLSessionDownloadDelegate

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/*
当一个下载task任务完成以后,这个方法会被调用。我们可以在这里移动或者复制download的数据
*/
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask
didFinishDownloadingToURL:(NSURL *)location{

}
/*
获取下载进度
*/
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask
didWriteData:(int64_t)bytesWritten
totalBytesWritten:(int64_t)totalBytesWritten
totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite{

}
/*
重启一个下载任务(比如下载一半后停止然后过一点时间继续)。如果下载出错,`NSURLSessionDownloadTaskResumeData`里面包含重新开始下载的数据。
*/
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask
didResumeAtOffset:(int64_t)fileOffset
expectedTotalBytes:(int64_t)expectedTotalBytes{

}

7 NSURLSession的综合使用案列

分别用三种不同方式下载一张图片然后在imageView上显示。

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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
#import "ViewController.h"

static NSString *const bigPic = @"http://i1.piimg.com/4851/d1498fea89ae3bc1.png";
static NSString *const smallPic = @"http://i1.piimg.com/4851/97aef4680d359905.png";

@interface ViewController ()<NSURLSessionDelegate>
@property (weak, nonatomic) IBOutlet UIImageView *imageView;
@property(nonatomic,strong)NSMutableData *data;
@end

@implementation ViewController

- (void)viewDidLoad {
[super viewDidLoad];

// Do any additional setup after loading the view, typically from a nib.
}

- (IBAction)requestDataTest:(id)sender {
[self clear];
NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:[[NSOperationQueue alloc] init]];
NSURLRequest *request = [[NSURLRequest alloc]initWithURL:[NSURL URLWithString:bigPic]];
NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request];
[dataTask resume];
}


- (IBAction)requestDownloadTest:(id)sender {
[self clear];
NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:[[NSOperationQueue alloc] init]];
NSURLRequest *request = [[NSURLRequest alloc]initWithURL:[NSURL URLWithString:bigPic]];
NSURLSessionDownloadTask *dataTask = [session downloadTaskWithRequest:request];
[dataTask resume];
}

-(IBAction)requestBlockTaskTest:(id)sender{
[self clear];
NSURLSession *session = [NSURLSession sharedSession];
NSURLRequest *request = [[NSURLRequest alloc]initWithURL:[NSURL URLWithString:bigPic]];
NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
UIImage *image = [[UIImage alloc]initWithData:data];
self.imageView.image = image;
}];
[dataTask resume];
}

-(void)clear{
self.imageView.image = nil;
}

//==============================NSURLSessionDelegate========================
#pragma NSURLSessionDelegate
//当一个session遇到系统错误或者未检测到的错误的时候,就会调用这个方法。
- (void)URLSession:(NSURLSession *)session didBecomeInvalidWithError:(nullable NSError *)error{

}
//当请求需要认证、或者https证书认证的时候,我们就需要在这个方法里面处理。
- (void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge
completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential * _Nullable credential))completionHandler{

}
//如果应用进入后台、这个方法会被调用。我们在这里可以对session发起的请求做各种操作比如请求完成的回调等。
- (void)URLSessionDidFinishEventsForBackgroundURLSession:(NSURLSession *)session {

}

//==================================NSURLSessionTaskDelegate====================
#pragma NSURLSessionTaskDelegate
/*
当请求重定向的时候调用这个方法。我们必须设置一个新的`NSURLRequest`对象传入completionHandler来重定向新的请求,但是当`session`是background模式的时候,这个方法不会被调用。
*/
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task
willPerformHTTPRedirection:(NSHTTPURLResponse *)response
newRequest:(NSURLRequest *)request
completionHandler:(void (^)(NSURLRequest * _Nullable))completionHandler{

}
/*
当请求需要认证的时候调用这个方法。如果没有实现这个代理,那么请求认证这个过程不会被调用。
*/
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task
didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge
completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential * _Nullable credential))completionHandler{

}
/*
如果请求需要一个新的请求体时,这个方法就会被调用。比如认证失败的时候,我们可以通过这个机会从新认证。
*/
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task
needNewBodyStream:(void (^)(NSInputStream * _Nullable bodyStream))completionHandler{

}
/*
当我们上传数据的时候,我们可以通过这个代理方法获取上传进度。
*/
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task
didSendBodyData:(int64_t)bytesSent
totalBytesSent:(int64_t)totalBytesSent
totalBytesExpectedToSend:(int64_t)totalBytesExpectedToSend{
NSLog(@"");
}
/*
当task的统计信息收集好了以后,调用这个方法。
*/
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didFinishCollectingMetrics:(NSURLSessionTaskMetrics *)metrics {

}
/*
当一个task出错的时候,会调用这个方法。如果error是nil,也会调用这个方法,表示task完成。
*/
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task
didCompleteWithError:(nullable NSError *)error{
NSLog(@"数据返回以后,不管有错没错都回调用,如果没错,error及时nil");
if (self.data) {
self.imageView.image = [UIImage imageWithData:self.data];
self.data = nil;
}
}

//==================================NSURLSessionDataDelegate=====================================
#pragma NSURLSessionDataDelegate
/*
当一个task接收到返回信息。当所有信息都接收完毕以后,completionHandler会被调用。我们可以在这里取消一个网络请求或者把一个datatask转换为downloadtask。如果没有实现这个代理方法,我们也可以通过task的response属性获取到对应的数据。background模式的uploadtask不会调用这个方法。
*/
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask
didReceiveResponse:(NSURLResponse *)response
completionHandler:(void (^)(NSURLSessionResponseDisposition disposition))completionHandler{
self.data = nil;
self.data = [NSMutableData data];
// 允许处理服务器的响应,才会继续接收服务器返回的数据
completionHandler(NSURLSessionResponseAllow);
}
/*
当一个datatask转换为一个downloadtask以后会调用。
*/
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask
didBecomeDownloadTask:(NSURLSessionDownloadTask *)downloadTask{

}
/*
暂时忽略,这个是和数据流相关的。不管了
*/
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask
didBecomeStreamTask:(NSURLSessionStreamTask *)streamTask{

}
/*
当data可以使用的时候,调用这个方法。我们可以在这里获取data。
*/
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask
didReceiveData:(NSData *)data{
[self.data appendData:data];
NSLog(@"具体数据在URLSession:(NSURLSession *)session task:(NSURLSessionTask *)taskdidCompleteWithError:(nullable NSError *)error处理");
}
/*
允许我们在这里调用completionHandler缓存data,或者传入nil来禁止缓存
*/
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask
willCacheResponse:(NSCachedURLResponse *)proposedResponse
completionHandler:(void (^)(NSCachedURLResponse * _Nullable cachedResponse))completionHandler{

}
//==================================NSURLSessionDownloadTask=================================
#pragma NSURLSessionDownloadTask
/*
当一个下载task任务完成以后,这个方法会被调用。我们可以在这里移动或者复制download的数据
*/
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask
didFinishDownloadingToURL:(NSURL *)location{
NSString *path = location.absoluteString;
UIImage *image = [[UIImage alloc]initWithData:[NSData dataWithContentsOfURL:location]];
self.imageView.image = image;
NSLog(@"数据下载完成以后,会保存在一个location的地方。%@",location);
}
/*
获取下载进度
*/
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask
didWriteData:(int64_t)bytesWritten
totalBytesWritten:(int64_t)totalBytesWritten
totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite{
NSLog(@"总得数据大小%lld----",bytesWritten);
}
/*
重启一个下载任务(比如下载一半后停止然后过一点时间继续)。如果下载出错,`NSURLSessionDownloadTaskResumeData`里面包含重新开始下载的数据。
*/
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask
didResumeAtOffset:(int64_t)fileOffset
expectedTotalBytes:(int64_t)expectedTotalBytes{

}
@end

...

...

00:00
00:00