发送网络请求我们之前用的一直都是NSURLConnection,在ios7.0之后出了个NSURLSession。
用NSURLConnection发送的网络请求的过程是URL-URLRequest-URLConnection。也就是先创建个URL,然后去创建个请求,再发送请求,获取响应。
而NSURLSession就是用来代替NSURLConnection的,支持后台运行的网络任务
暂停、停止、重启网络任务,我们就可以不用自己去封装NSOperation,在NSOperation中做这个事情了。
还有就是下载、断点续传、上传、获取下载和上传的进度都是支持的。
NSURLSession可以发起DataTask、UploadTask、还有就是DownloadTask任务。这三种任务苹果都是封装好了的,这些任务默认是挂起的,我们要去开启,为什么默认是挂起了,因为NSURLSession支持暂停,暂停之后其实就是挂起状态。
NSURLSessionConfigration是配置请求的信息的.可以设置请求头,可以设置超时时长,可以设置缓存策略,可以设置是否允许蜂窝网络访问
使用如下,默认发送GET请求
- (void)dataTask {
NSURL *url = [NSURL URLWithString:@"//"];
[[[NSURLSession sharedSession] dataTaskWithURL:url completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable
response, NSError * _Nullable error) {
id json = [NSJSONSerialization JSONObjectWithData:data options:0 error:NULL];
NSLog(@"%@",json);
}] resume];
}
发送POST请求
//发送post请求
- (void)dataTask1 {
NSURL *url = [NSURL URLWithString:@"//"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
request.HTTPMethod = @"post";
NSString *body = @"username=12345&password=123";
request.HTTPBody = [body dataUsingEncoding:NSUTF8StringEncoding];
[[[NSURLSession sharedSession] dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse *
_Nullable response, NSError * _Nullable error) {
id json = [NSJSONSerialization JSONObjectWithData:data options:0 error:NULL];
NSLog(@"%@",json);
}] resume];
}
下载DownLoadTask的任务,内存不会暴涨,而且也是一点一点下载的
默认把文件下载到沙盒中的tmp文件夹,为什么?因为从网络上下载文件是zip文件最多,因为压缩文件可以节省用户的流量。通常情况下,下载完zip文件需要解压,所以可以解压到另一个目录,然后tmp文件夹里面的内容,系统可能在应用没运行时就删除该目录下的文件,所以此目录适合保存应用中的一些临时文件,用完就删除。
下载任务代码
- (void)downloadTask {
NSURL *url = [NSURL URLWithString:@"//"];
[[[NSURLSession sharedSession] downloadTaskWithURL:url completionHandler:^(NSURL * _Nullable location, NSURLResponse *
_Nullable response, NSError * _Nullable error) {
//回调是在子线程上执行的
//输出下载文件所在的文件夹
NSLog(@"%@",location);
//获取Document的文件路径,然后拼接一个文件
NSString *doc = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject]
stringByAppendingPathComponent:@"jj.cs"];
//复制到其他位置,可以保存到其他的位置
[[NSFileManager defaultManager] copyItemAtPath:location.path toPath:doc error:NULL];
}] resume];
}
我们如果要跟踪下载进度的话,我们就要去使用NSURLSession的代理方法,跟踪下载进度我们不能直接使用shared,因为下载进度的获取需要用到代理,而shared不能去设置代理,我们可以去定义一个全局的属性,因为我们可能多次的去下载,然后我们给它进行懒加载,用到的时候去调用就可以了,使用NSURLSessionDownloadDelegate。我们用了代理的方法去监听下载过程的话,我们发送请求就不能用回调的方法了。因为如果我们再去写回调的话,只有回调的方法会执行,代理的方法就不会执行了什么叫调用回调的方法就是用 [[[NSURLSession sharedSession] downloadTaskWithURL:url completionHandler这个方法去请求。
#import "ViewController.h"
@interface ViewController () <NSURLSessionDownloadDelegate>
//设置全局的session
@property (nonatomic, strong) NSURLSession *session;
//生成的任务
@property (nonatomic, strong) NSURLSessionDownloadTask *downloadTask;
//保存续传的数据
@property (nonatomic, strong) NSData *resumeData;
@end
@implementation ViewController
//开始下载
- (IBAction)start:(id)sender {
[self download];
}
//暂停下载
- (IBAction)pause:(id)sender {
[self.downloadTask cancelByProducingResumeData:^(NSData * _Nullable resumeData) {
//保存续传的数据,包含一些信息比如说已经下载的字节,下载的地址之类的
self.resumeData = resumeData;
//把续传数据保存到沙盒中,可以在退出程序的时候继续读取
NSString *path = [NSTemporaryDirectory() stringByAppendingPathComponent:@"kk.tmp"];
[self.resumeData writeToFile:path atomically:YES];
NSLog(@"%@",path);
//设置为nil之后再点击暂停,第一行相当于给nil发消息了
self.downloadTask = nil;
// NSLog(@"%@",resumeData);
}];
}
//继续下载
- (IBAction)resume:(id)sender {
//从沙盒中获取续传数据
NSString *path = [NSTemporaryDirectory() stringByAppendingPathComponent:@"kk.tmp"];
NSFileManager *fileManager = [NSFileManager defaultManager];
//判断文件是否存在
if ([fileManager fileExistsAtPath:path]) {
self.resumeData = [NSData dataWithContentsOfFile:path];
}
//判断续传数据是否存在,不存在就返回nil,防止继续多点产生的影响
if (self.resumeData == nil) {
return;
}
self.downloadTask = [self.session downloadTaskWithResumeData:self.resumeData];
//继续任务
[self.downloadTask resume];
//防止点击很多次继续按钮出现的连续下载
self.resumeData = nil;
}
//懒加载
- (NSURLSession *)session {
if (_session == nil) {
NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];
//设置在主队列中执行代理方法,当delegateQueue为nil的时候效果和[NSOperation new]一样的,在子线程上执行。这里的队列也决定了回调在哪里执行
_session = [NSURLSession sessionWithConfiguration:config delegate:self delegateQueue:[NSOperationQueue mainQueue]];
}
return _session;
}
//开始下载
- (void)download {
NSURL *url = [NSURL URLWithString:@"网址"];
NSURLSessionDownloadTask *downloadTask = [self.session downloadTaskWithURL:url];
self.downloadTask = downloadTask;
[downloadTask resume];
}
//代理方法
//下载完成
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location {
NSLog(@"%@",[NSThread currentThread]);
NSLog(@"下载完成:%@",location);
// 取消操作 session一旦使用了下面这个方法之后,session无法再次使用
[self.session invalidateAndCancel];
//下载完成,再使session无效
//[self.session finishTasksAndInvalidate];
//调用为nil,就是防止我们再去做下载操作的时候程序会直接崩溃
self.session = nil;
}
//续传的方法
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didResumeAtOffset:(int64_t)fileOffset expectedTotalBytes:(int64_t)expectedTotalBytes {
NSLog(@"续传数据");
}
//获取进度的方法
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite {
float process = totalBytesWritten * 1.0 /totalBytesExpectedToWrite;
NSLog(@"下载进度: %f",process);
}
@end
如果我们在上传的文件的时候创建NSURLSession的对象用了有代理参数的方法,我们去发送请求的时候还是可以用回调的方法的,因为都会执行,只是代理中处理执行完的时候的那个方法不会执行