iOS网络编程(NSURLSession)
原文地址:https://www.jianshu.com/p/78964aac72d5
1. NSURLSesscion使用步骤
- 使用NSURLSession对象创建Task
- 执行Task
Task的类型
task类型.png2.NSURLSesscion 常用方法
获得Session
获得共享的Session
+ (NSURLSession *)sharedSession;
自定义Session
+ (NSURLSession *)sessionWithConfiguration:(NSURLSessionConfiguration *)configuration delegate:(id <NSURLSessionDelegate>)delegate delegateQueue:(NSOperationQueue *)queue;
Session常用方法
常见方法
- (void)suspend; // 暂停
- (void)resume; // 恢复
- (void)cancel; // 取消
@property (readonly, copy) NSError *error; // 错误
@property (readonly, copy) NSURLResponse *response; // 响应
// 取消任务 这个方法可以拿到恢复下载需要的数据
- (void)cancelByProducingResumeData:(void (^)(NSData *resumeData))completionHandler;
3. NSURLSesscion 简单使用
1. GET请求
- (void)sessionGetMethod
{
//获取session单例
NSURLSession *session = [NSURLSession sharedSession];
//创建url
NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/login"];
//根据url创建request请求
NSURLRequest *request = [NSURLRequest requestWithURL:url];
//以block形式根据request请求为参数创建任务 返回参数-data:响应体 response:响应头 error:错误信息
NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:nil];
NSLog(@"%@---%@",[dict descriptionWithLocale:nil], [NSThread currentThread]);
}];
//开始任务
[dataTask resume];
}
运行结果如下:
2018-05-08 10:14:00.392311+0800 NSURLSesscion[3394:418080] {
error = "用户名不存在";
}---<NSThread: 0x600000274b80>{number = 4, name = (null)}
2. POST请求
- (void)sessionPostMethod
{
//获取session单例
NSURLSession *session = [NSURLSession sharedSession];
//创建url
NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/login"];
//根据url创建可变request请求
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
//指定请求方式为post
request.HTTPMethod = @"POST";
//指定请求体
request.HTTPBody = [@"username=520it&pwd=520it&type=JSON" dataUsingEncoding:NSUTF8StringEncoding];
//以block形式根据request请求为参数创建任务 返回参数-data:响应体 response:响应头 error:错误信息
NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:nil];
NSLog(@"%@---%@",[dict descriptionWithLocale:nil], [NSThread currentThread]);
}];
//开始任务
[dataTask resume];
}
运行结果如下:
2018-05-08 10:08:08.601784+0800 NSURLSesscion[3291:407316] {
success = "登录成功";
}---<NSThread: 0x604000265fc0>{number = 4, name = (null)}
注意:通过打印可以看出回调方法在子线程中调用,如果在回调方法中拿到数据刷新UI,必须要回到主线程刷新UI。
3.代理方法请求 <NSURLSessionDataDelegate>
- (void)startButtonTouchesBegan:(id)event
{
//创建session
NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:[NSOperationQueue mainQueue]];
//创建url
NSURL *url =[NSURL URLWithString:@"http://120.25.226.186:32812/login?username=520it&pwd=520it&type=JSON"];
//创建reqauest请求
NSURLRequest *request = [NSURLRequest requestWithURL:url];
//创建任务
NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request];
//开始任务
[dataTask resume];
}
#pragma mark - NSURLSessionDataDelegate代理方法
// 接收到服务器响应的时候调用
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveResponse:(nonnull NSURLResponse *)response completionHandler:(nonnull void (^)(NSURLSessionResponseDisposition))completionHandler
{
NSLog(@"didReceiveResponse 接受到服务器响应");
// completionHandler 控制是否接受服务器返回的数据
/**
typedef NS_ENUM(NSInteger, NSURLSessionResponseDisposition) {
NSURLSessionResponseCancel = 0, // 默认,表示取消接受数据,和[task cancel]相同
NSURLSessionResponseAllow = 1, // 接受数据
NSURLSessionResponseBecomeDownload = 2, //Turn this request into a download
NSURLSessionResponseBecomeStream NS_ENUM_AVAILABLE(10_11, 9_0) = 3, //Turn this task into a stream task
}
*/
completionHandler(NSURLSessionResponseAllow);
}
// 接收到服务器返回数据时调用,会调用多次
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data
{
NSLog(@"didReceiveData 接受到服务器返回数据");
}
// 当请求完成之后调用,如果请求失败error有值
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error
{
NSLog(@"didCompleteWithError 请求完成");
}
运行结果如下:
2018-05-08 10:37:40.426230+0800 NSURLSesscion[3760:455576] didReceiveResponse 接受到服务器响应
2018-05-08 10:37:40.426556+0800 NSURLSesscion[3760:455576] didReceiveData 接受到服务器返回数据
2018-05-08 10:37:40.426888+0800 NSURLSesscion[3760:455576] didCompleteWithError 请求完成
4.NSURLSessionConfiguration 配置简单说明
NSURLSessionConfiguration 对象用于初始化 NSURLSession 对象。当 NSURLSession 开启多个任务 Task 的时候可以用 NSURLSessionConfiguration 对象统一配置。
NSURLSessionConfiguration有三个类构造函数:
-
defaultSessionConfiguration
返回标准默认配置,一般我们都使用这个 -
ephemeralSessionConfiguration
返回一个预设配置,没有持久性存储的缓存,Cookie或证书。可以用来实现像"无痕浏览" -
backgroundSessionConfiguration
独特之处在于,它会创建一个后台会话。它甚至可以在应用程序挂起,退出,崩溃的情况下运行上传和下载任务
其他配置:
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
// 请求超时时间
configuration.timeoutIntervalForRequest = 10;
// 加载资源超时时间
configuration.timeoutIntervalForResource = 10;
// 蜂窝网络状态下是否可用
configuration.allowsCellularAccess = YES;
3. NSURLSesscion 文件下载
1. NSURLSessionDownloadTask实现断点下载
NSURLSession 提供了专用用来下载的 Task ,NSURLSessionDownloadTask,使用NSURLSessionDownloadTask 的代理方法或者本身提供的方法可以很轻松的实现断点下载。
- (void)downloadButtonTouchesBegan:(id)event
{
[self sessionDownloadMethod];
}
- (void)sessionDownloadMethod
{
NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:[NSOperationQueue mainQueue]];
NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/resources/videos/minion_03.mp4"];
self.downloadTask = [session downloadTaskWithURL:url];
[self.downloadTask resume];
}
- (void)cancelButtonTouchesBegan:(id)event
{
[self.downloadTask cancelByProducingResumeData:^(NSData * _Nullable resumeData) {
}];
}
#pragma mark - NSURLSessionDownloadDelegate代理方法
// 1.当接收到数据的时候,写数据,该方法会调用多次
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite
{
//bytesWritten:本次写入数据的大小
//totalBytesWritten:已经下载完成的数据大小
//totalBytesExpectedToWrite:文件大小
//可以在这个方法中监听下载的进度 totalBytesWritten/totalBytesExpectedToWrite
NSLog(@"本次写入数据大小:%lld --- 已经下载完成的数据大小:%lld --- :文件大小:%lld ",bytesWritten,totalBytesWritten,totalBytesExpectedToWrite);
float number = 100.0 * totalBytesWritten / totalBytesExpectedToWrite;
[self.downloadButton setTitle:[NSString stringWithFormat:@"%.1f %%",number] forState:UIControlStateNormal];
}
// 2.恢复下载的时候调用
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didResumeAtOffset:(int64_t)fileOffset expectedTotalBytes:(int64_t)expectedTotalBytes
{
NSLog(@"didResumeAtOffset");
}
// 3.下载完成之后调用
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location
{
// location :下载文件的存储位置,在沙盒tmp文件中。
// tmp文件保存应用运行时所需的临时数据,使用完毕后会将相应的文件从该目录中删除,应用程序关闭时,系统会清除该目录下的文件
// 程序下载完成之后我们可以将tmp中下载的文件移动到沙盒中保存。
// NSLog(@"didFinishDownloading 下载完成,路径为:%@",location);
NSFileManager *manager = [NSFileManager defaultManager];
NSData *data = [manager contentsAtPath:location.path];
//保存下载的文件到沙盒
NSString *caches = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];
//拼接文件全路径
NSString *fullPath = [caches stringByAppendingPathComponent:@"abc.mp4"];
//写入数据到文件
[data writeToFile:fullPath atomically:YES];
}
通过以上方法可以很轻松的实现断点下载,但是使用 NSURLSessionDownloadTask 实现还有一些缺点,我们只有在下载完成之后才能拿到下载完成的文件,那么当我们下载到一半的时候,我们点击暂停,或者在下载过程中,直接关闭退出程序,此时因为文件是保存在内存中的,所以之前下载的文件已经不存在了,当我们重新运行程序,就需要重新下载。这种不可操纵性显然不是我们想要的。因此我们还是要使用 NSURLSessiondataTask 来实现离线断点下载。
2. NSURLSessiondataTask实现文件离线断点下载
原理:首先利用输出流实现边下载边存储数据到沙盒,另外在第一次接收到响应的时候将下载文件的大小也存储在沙盒中。然后当退出程序重新运行的时候,查看沙盒中是否有已经下载的文件,如果有就获取已经下载文件的大小,并取出沙盒中存储的文件总大小,将下载进度显示在界面,然后接着拼接下载。如果没有,则从0开始下载。
#import "DownloadViewController.h"
#define FileName @"chip.mp4"
#define FileLength @"chip.xx"
@interface DownloadViewController ()<NSURLSessionDataDelegate>
@property (strong, nonatomic) NSOutputStream *stream; //输出流
@property (assign, nonatomic) NSInteger totalLength; //总大小
@property (assign, nonatomic) NSInteger currentLength; //已经下载大小
@property (nonatomic, strong) NSURLSession *session;
@property (nonatomic, strong) NSURLSessionDataTask *dataTask;
@property (strong, nonatomic) UIProgressView *progressView;
@property (strong, nonatomic) UIButton *playBtn;
@property (strong, nonatomic) UIButton *startBtn;
@property (strong, nonatomic) UIButton *pauseBtn;
@property (strong, nonatomic) UIButton *deleteBtn;
@end
@implementation DownloadViewController
- (NSURLSessionDataTask *)dataTask
{
if (!_dataTask) {
self.currentLength = [self getCurrentLength];
NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/resources/videos/minion_02.mp4"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
NSString *range = [NSString stringWithFormat:@"bytes=%zd-",self.currentLength];
[request setValue:range forHTTPHeaderField:@"Range"];
_dataTask = [self.session dataTaskWithRequest:request];
}
return _dataTask;
}
- (NSURLSession *)session{
if (!_session) {
_session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:[NSOperationQueue mainQueue]];
}
return _session;
}
- (UIProgressView *)progressView
{
if (!_progressView) {
_progressView = ({
UIProgressView *progressView = [[UIProgressView alloc] init];
progressView.frame = CGRectMake(50, 100, 200, 50);
progressView.tintColor = [UIColor redColor];
progressView;
});
}
return _progressView;
}
- (UIButton *)playBtn
{
if (!_playBtn) {
_playBtn = ({
UIButton *button = [[UIButton alloc] init];
button.frame = CGRectMake(200, 400, 100, 50);
button.backgroundColor = [UIColor redColor];
[button setTitle:@"播放" forState:UIControlStateNormal];
[button setTitleColor:[UIColor lightGrayColor] forState:UIControlStateDisabled];
[button setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
[button addTarget:self action:@selector(playBtnEvent:) forControlEvents:UIControlEventTouchUpInside];
button.enabled = NO;
button;
});
}
return _playBtn;
}
- (UIButton *)pauseBtn
{
if (!_pauseBtn) {
_pauseBtn = ({
UIButton *button = [[UIButton alloc] init];
button.frame = CGRectMake(200, 300, 100, 50);
button.backgroundColor = [UIColor redColor];
[button setTitle:@"暂停" forState:UIControlStateNormal];
[button addTarget:self action:@selector(pauseBtnEvent:) forControlEvents:UIControlEventTouchUpInside];
button;
});
}
return _pauseBtn;
}
- (UIButton *)startBtn
{
if (!_startBtn) {
_startBtn = ({
UIButton *button = [[UIButton alloc] init];
button.frame = CGRectMake(200, 200, 100, 50);
button.backgroundColor = [UIColor redColor];
[button setTitle:@"开始/继续" forState:UIControlStateNormal];
[button addTarget:self action:@selector(startBtnEvent:) forControlEvents:UIControlEventTouchUpInside];
button;
});
}
return _startBtn;
}
- (UIButton *)deleteBtn
{
if (!_deleteBtn) {
_deleteBtn = ({
UIButton *button = [[UIButton alloc] init];
button.frame = CGRectMake(200, 500, 100, 50);
button.backgroundColor = [UIColor redColor];
[button setTitle:@"删除" forState:UIControlStateNormal];
[button addTarget:self action:@selector(deleteBtnEvent:) forControlEvents:UIControlEventTouchUpInside];
button;
});
}
return _deleteBtn;
}
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = [UIColor whiteColor];
[self.view addSubview:self.progressView];
[self.view addSubview:self.startBtn];
[self.view addSubview:self.pauseBtn];
[self.view addSubview:self.playBtn];
[self.view addSubview:self.deleteBtn];
NSString *caches = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];
NSString *filePath = [caches stringByAppendingPathComponent:FileName];
NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithContentsOfFile:filePath];
if (dict) {
self.progressView.progress = 1.0 * [self getCurrentLength] / [dict[filePath] integerValue];
if (self.progressView.progress == 1) {
self.playBtn.enabled = YES;
}
}
// Do any additional setup after loading the view.
}
- (NSInteger)getCurrentLength
{
NSString *caches = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];
NSString *filePath = [caches stringByAppendingPathComponent:FileName];
NSFileManager *manager = [NSFileManager defaultManager];
NSDictionary *dict = [manager attributesOfItemAtPath:filePath error:nil];
return [dict[@"NSFileSize"] integerValue];
}
- (void)saveTotal:(NSInteger)length
{
NSLog(@"开始储存文件大小");
NSString *caches = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];
NSString *filePath = [caches stringByAppendingPathComponent:FileLength];
NSMutableDictionary *dict = [NSMutableDictionary dictionary];
[dict setObject:@(length) forKey:FileLength];
[dict writeToFile:filePath atomically:YES];
}
- (void)startBtnEvent:(id)event
{
[self.dataTask resume];
}
- (void)pauseBtnEvent:(id)event
{
[self.dataTask suspend];
}
- (void)playBtnEvent:(id)event
{
UIAlertController *action = [UIAlertController alertControllerWithTitle:@"播放" message:@"可以播放" preferredStyle:UIAlertControllerStyleAlert];
[self presentViewController:action animated:YES completion:nil];
}
- (void)deleteBtnEvent:(id)event
{
NSString *caches = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];
NSString *filePath = [caches stringByAppendingPathComponent:FileName];
NSFileManager *manager = [NSFileManager defaultManager];
[manager removeItemAtPath:filePath error:nil];
self.currentLength = 0;
NSLog(@"删除成功");
self.progressView.progress = 0;
}
#pragma mark - NSURLSessionDataDelegate 代理方法
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveResponse:(NSURLResponse *)response completionHandler:(void (^)(NSURLSessionResponseDisposition))completionHandler
{
// 拿到文件总大小 获得的是当次请求的数据大小,当我们关闭程序以后重新运行,开下载请求的数据是不同的 ,所以要加上之前已经下载过的内容
NSLog(@"接收到服务器响应");
self.totalLength = response.expectedContentLength + self.currentLength;
// 把文件总大小保存的沙盒 没有必要每次都存储一次,只有当第一次接收到响应,self.currentLength为零时,存储文件总大小就可以了
if (self.currentLength == 0) {
[self saveTotal:self.totalLength];
}
NSString *caches = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];
NSString *filePath = [caches stringByAppendingPathComponent:FileName];
NSLog(@"%@",filePath);
NSOutputStream *stream = [[NSOutputStream alloc] initToFileAtPath:filePath append:YES];
[stream open];
self.stream = stream;
completionHandler(NSURLSessionResponseAllow);
}
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data
{
self.currentLength += data.length;
//输出流写数据
[self.stream write:data.bytes maxLength:data.length];
NSLog(@"%f",1.0 * self.currentLength / self.totalLength);
self.progressView.progress = 1.0 * self.currentLength / self.totalLength;
}
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error
{
[self.stream close];
self.stream = nil;
NSLog(@"didCompleteWithError 请求完成");
self.playBtn.enabled = YES;
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
/*
#pragma mark - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
// Get the new view controller using [segue destinationViewController].
// Pass the selected object to the new view controller.
}
*/
@end
4. NSURLSessiond上传文件
1. NSURLSessionUploadTask上传文件
- (void)uploadButtonEvent:(id)event
{
NSURLSession *session = [NSURLSession sharedSession];
NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/upload"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
request.HTTPMethod = @"POST";
NSString *header = [NSString stringWithFormat:@"multipart/form-data; boundary=%@",Kboundary];
[request setValue:header forHTTPHeaderField:@"Content-Type"];
// session上传不需要设置请求体,如果数据在request中会被忽略。
NSURLSessionUploadTask *uploadTask = [session uploadTaskWithRequest:request fromData:[self getBody] completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
NSLog(@"%@",[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]);
}];
[uploadTask resume];
}
- (NSData *)getBody
{
NSMutableData *fileData = [NSMutableData data];
//文件参数格式
/*
--分隔符
Content-Disposition: form-data; name="file"; filename="123.png"
Content-Type: image/png
空行
文件数据
*/
NSString *str = [NSString stringWithFormat:@"--%@",Kboundary];
//--分隔符
[fileData appendData:[str dataUsingEncoding:NSUTF8StringEncoding]];
//换行
[fileData appendData:KNewLine];
//Content-Disposition: form-data; name="file"; filename="123.png"
[fileData appendData:[@"Content-Disposition: form-data; name=\"file\"; filename=\"123.png\"" dataUsingEncoding:NSUTF8StringEncoding]];
//换行
[fileData appendData:KNewLine];
//Content-Type: image/png
[fileData appendData:[@"Content-Type: image/png" dataUsingEncoding:NSUTF8StringEncoding]];
//换行
[fileData appendData:KNewLine];
//空行
[fileData appendData:KNewLine];
//换行
[fileData appendData:KNewLine];
//文件数据
UIImage *image = [UIImage imageNamed:@"123"];
NSData *imageData = UIImagePNGRepresentation(image);
[fileData appendData:imageData];
//换行
[fileData appendData:KNewLine];
//5.2 非文件参数
/*
--分隔符
Content-Disposition: form-data; name="username"
空行
yy
*/
[fileData appendData:[str dataUsingEncoding:NSUTF8StringEncoding]];
[fileData appendData:KNewLine];
[fileData appendData:[@"Content-Disposition: form-data; name=\"username\"" dataUsingEncoding:NSUTF8StringEncoding]];
[fileData appendData:KNewLine];
[fileData appendData:KNewLine];
[fileData appendData:KNewLine];
[fileData appendData:[@"yy" dataUsingEncoding:NSUTF8StringEncoding]];
[fileData appendData:KNewLine];
//5.3 结尾标识
/*
--分隔符--
*/
[fileData appendData:[[NSString stringWithFormat:@"--%@--",Kboundary] dataUsingEncoding:NSUTF8StringEncoding]];
[fileData appendData:KNewLine];
return fileData;
}
运行结果如下:
2018-05-09 14:58:38.101663+0800 NSURLSesscion[11074:1637141] {"success":"上传成功"}
2. NSURLSessionUploadTask 代理方法上传
NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:[NSOperationQueue mainQueue]];
#pragma mark NSURLSessionDataDelegate 代理方法
/*
bytesSent:本次上传数据大小
totalBytesSent:总共上传了多少
totalBytesExpectedToSend:文件大小
*/
-(void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didSendBodyData:(int64_t)bytesSent totalBytesSent:(int64_t)totalBytesSent totalBytesExpectedToSend:(int64_t)totalBytesExpectedToSend
{
NSLog(@"%f",1.0 *totalBytesSent /totalBytesExpectedToSend);
}
// 上传结束
-(void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error
{
NSLog(@"上传结束");
}
@end
5. NSURLSession 内存释放问题
NSURLSession 需要释放,不然会引起内存泄漏
-(void)dealloc
{
//注意:在不用的时候一定要调用该方法来释放,不然会出现内存泄露问题
//方法一:取消所有过去的会话和任务
[self.session invalidateAndCancel];
//方法二:可在释放时做一些操作
[self.session resetWithCompletionHandler:^{
// 释放时做的操作
}];
}