平时在项目中一直是用网络请求的第三方框架 AFNetwork和 ASIHTTPRequest比较多一些。最近还是想系统的从苹果官方的原生网络类开始做一个详细的了解。
原生网络请求类
首先苹果官方提供的原生网络请求类包括:NSURLConnection和NSURLSession。
其中,NSURLConnection从iOS9开始不被官方推荐使用了,而推荐使用从iOS7开始出现的NSURLSession。
(一)、NSURLConnection
概述:
我们通过提供 NSURLRequest对象给NSURLConnection,来异步的加载URL的内容。
NSURLConnection的接口比较少,只提供了开始和取消URL请求的操作。
NSURLRequest不能修改请求方式,默认GET请求;
NSMutableURLRequest可以修改请求方式。
NSURLConnection请求的方式
NSURLConnection请求的方式有三种:
1、同步请求:
NSURLConnection的类目 NSURLConnectionSynchronousLoading提供了同步加载的方法:
+ (nullable NSData *)sendSynchronousRequest:(NSURLRequest *)request returningResponse:(NSURLResponse * _Nullable * _Nullable)response error:(NSError **)error API_DEPRECATED("Use [NSURLSession dataTaskWithRequest:completionHandler:] (see NSURLSession.h", macos(10.3,10.11), ios(2.0,9.0), tvos(9.0,9.0)) __WATCHOS_PROHIBITED;
2、Block异步请求
NSURLConnection的类目 NSURLConnectionQueuedLoading提供了异步加载的方法:
+ (void)sendAsynchronousRequest:(NSURLRequest*) request
queue:(NSOperationQueue*) queue
completionHandler:(void (^)(NSURLResponse* _Nullable response, NSData* _Nullable data, NSError* _Nullable connectionError)) handler API_DEPRECATED("Use [NSURLSession dataTaskWithRequest:completionHandler:] (see NSURLSession.h", macos(10.7,10.11), ios(5.0,9.0), tvos(9.0,9.0)) __WATCHOS_PROHIBITED;
3、代理异步请求
逻辑上来讲,NSURLConnectionDownloadDelegate,NSURLConnectionDataDelegate,都是NSURLConnectionDelegate的子类。
我们可以通过遵守NSURLConnectionDelegate,NSURLConnectionDownloadDelegate,NSURLConnectionDataDelegate协议的代理对象来创建URLconnection对象。
当URL请求加载时,这些connection会调用代理的方法来提供加载进度和状态。也可以调用代理方法来复写这些connection的默认行为(比如,指定如何处理特定的重定向)。
当加载失败时,调用NSURLConnectionDelegate的代理方法:
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error;
当加载完成并加载成功时,调用NSURLConnectionDelegate的代理方法:
- (void)connectionDidFinishLoading:(NSURLConnection *)connection;
和NSURLConnectionDownloadDelegate的代理方法:
//加载成功后提供下载文件的位置
- (void)connectionDidFinishDownloading:(NSURLConnection *)connection destinationURL:(NSURL *) destinationURL;
NSURLConnection三种请求的示例
1、同步请求
//发送同步请求,会阻塞主线程
NSURL *url = [NSURL URLWithString:@"https://www.baidu.com/"];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
NSHTTPURLResponse *response = nil;
NSError *error = nil;
NSData *syncData = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
NSString *str = [[NSString alloc] initWithData:syncData encoding:NSUTF8StringEncoding];
NSLog(@"syncData = %@", str);
2、异步请求
//发送异步请求
NSURL *url = [NSURL URLWithString:@"https://www.baidu.com/"];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
[NSURLConnection sendAsynchronousRequest:request queue:[[NSOperationQueue alloc]init] completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
NSString *str = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(@"AsyncData = %@", str);
}];
3、代理异步请求
创建请求,并设置代理
- (void)pressbtn1
{
NSURL *url = [NSURL URLWithString: @"https://www.baidu.com/"];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
_connect = [NSURLConnection connectionWithRequest:request delegate:self];
}
代理方法
#pragma mark -NSURLConnectionDataDelegate
//接收到服务器响应时调用
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
//将响应码转化成为HHTTP响应码
NSHTTPURLResponse *res = (NSHTTPURLResponse *)response;
if(res.statusCode == 200)
{
NSLog(@"请求成功");
}
else if (res.statusCode == 404)
{
NSLog(@"没有找到文件");
}
else if(res.statusCode == 500)
{
NSLog(@"服务器内部错误");
}
}
//当接收到数据时调用
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
[_data appendData:data];
}
//当服务器数据返回完毕时调用
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
NSString *str = [[NSString alloc] initWithData:_data encoding:NSUTF8StringEncoding];
NSLog(@"代理 data = %@", str);
}
(二)、NSURLSession
概述:
NSURLSession类及其相关类提供了下载内容的API和很多代理方法,如支持认证,断点续传,当APP没有运行或者被挂起时,后台下载的功能。
NSURLSession支持HTTP/1.1,SPDY,HTTP/2协议。
使用NSURLSession的API,我们可以创建一个或多个会话,每个会话都协调管理一组相关的数据传输任务。
举个例子,在一个web浏览器中,我们可以为每个标签或窗口创建一个会话,可以为交互使用创建一个会话,也可以为后台下载创建另一个会话。
在每个会话里,APP可以添加一系列任务,每个任务都代表一个特定URL的请求。
会话的四种类型
在一个给定的URL会话中,所有的任务共享一个会话配置对象 NSURLSessionConfiguration,它定义了连接的配置方式,比如同时连接到单个主机的最大数,是否允许通过蜂窝网连接等等。
会话的方式取决于创建它的配置对象:
1、单例会话。单例共享的会话用于基本请求,没有配置对象。这种会话不可定制,但是如果要求不多的话,可以选择这种方式。我们可以通过调用sharedSession的类方法来访问该会话。
2、默认会话。默认会话和单例会话非常相似,但是我们可以使用代理获取更多的数据。我们可以调用NSURLSessionConfiguration类中的defaultSessionConfiguration方法创建默认的会话配置。
3、短会话。短会话和默认会话很相似,但是不会将cache,cookies或credential写入磁盘。可以通过调用NSURLSessionConfiguration类中的ephemeralSessionConfiguration方法创建短会话配置。
4、后台会话。后台会话可以在APP没有运行时在后台上传或者下载。可以通过调用NSURLSessionConfiguration类中的backgroundSessionConfiguration方法创建后台会话配置。
会话配置对象也包含了对 URLCache和 HTTPCookieStorage对象的引用,在做请求、处理响应和决定配置和请求类型时使用。
会话中的任务也会共享一个通用代理,使我们在各种事件发生时(比如认证失败时,数据从服务器到达时,数据准备好被缓存时等等),提供或获取信息。使用URL会话,当会话在执行任务时,会有一个事件逐步发生的列表,从而相应的代理方法会被调用。
另一方面,如果不需要代理提供的任何功能,我们也可以在创建会话时,通过传递nil来使用这个API,不提供任何功能。
注意:
会话对象保持着代理的强引用直到APP运行或会话明确无效。如果不废除这个会话,APP就会内存泄漏。
会话可以创建的任务类型
在会话中,我们可以创建上传数据到服务器的任务,也可以创建任务从服务器获取数据来作为磁盘文件或内存NSData对象。
NSURLSession的API提供了3种类型的任务:
1、Data任务。Data任务使用NSData对象发送或接收数据。Data任务旨在对服务器短而频繁的交互请求。
2、 Upload任务。上传任务和Data任务相似,但是它也可以发送数据(通常是文件形式),当APP不运行时,支持后台上传。
3、 Download任务。下载任务以文件形式获取数据,当APP不运行时,支持后台下载。
会话返回数据的方式
和大部分网络API一样,NSURLSession的API是高度异步的。它会以下面两种方式中的一种来返回数据,取决于你调用的方法:
1、当传输成功完成或者传输错误时,调用完成处理的block;
2、当接收到数据或传输完成时,调用session的代理。
NSURLSession的API还提供了查询状态和进度的属性,可以跟筠需要对任务当前的状态(随时注意状态变化)来做一些项目决策。
URL会话也支持取消,重新开始,继续,挂起任务,并支持继续下载挂起、下载取消、下载失败的功能。
URLSession的使用
使用NSURLSession类请求:
1、创建一个session配置。对于后台会话,这个配置必须包含唯一标识符。存储标识符,当APP崩掉或结束挂起时,使用它来重连会话。
2、创建会话,指定配置对象和代理。
3、在会话中创建任务对象,每个任务代表一个URL请求。
这些任务对象是NSURLSessionTask——NSURLSessionDataTask, NSURLSessionUploadTask, NSURLSessionDownloadTask,取决于你创建的方式。
每个任务的初始状态都是都是暂停状态。APP在任务中调用resume方法后,就开始下载指定资源。
开始任务后,会话调用代理方法的步骤:
1、如果与服务器第一次握手需要连接的身份认证(如SSL客户端认证),NSURLSession会调用代理方法
URLSession:task:didReceiveChallenge:completionHandler:
或
URLSession:didReceiveChallenge:completionHandler:
2、如果任务的数据从流中获取,NSURLSession调用代理方法
URLSession:task:needNewBodyStream:
来获取NSInputStream的实例为新的请求提供body数据。
3、在body内容第一次上传到服务器期间,代理定期会收到回调
URLSession:task:didSendBodyData:totalBytesSent:totalBytesExpectedToSend:
来报告上传的进度。
4、服务器发送响应。
5、如果响应指明要求认证,会话调用代理的
URLSession:task:didReceiveChallenge:completionHandler:
方法。回到第2步。
6、如果响应是HTTP重定向响应,NSURLSession对象调用代理的方法
URLSession:task:willPerformHTTPRedirection:newRequest:completionHandler:
代理方法使用所提供的NSURLRequest对象(遵循重定向),一个新的NSURLRequest对象(重定向到不同URL),或者nil(将重定向的响应体作为有效响应并作为结果返回)来调用所提供的completion处理回调。
如果要遵循重定向,回到第2步。
如果代理没有实现这个方法,重定向追踪最大重定向数。
7、对于通过调用
downloadTaskWithResumeData:
或
downloadTaskWithResumeData:completionHandler:
创建的下载(或重下载)任务,NSURLSession使用新任务对象调用代理方法
URLSession:downloadTask:didResumeAtOffset:expectedTotalBytes:
8、对于数据任务,NSURLSession对象调用代理方法
URLSession:dataTask:didBecomeDownloadTask:
,来决定是否转变数据任务为下载任务,然后调用处理回调来转变,继续,取消任务。如果APP选择将数据任务转变为下载任务,NSURLSession会使用新下载任务作为参数调用代理的方法。调用之后,代理不会收到来自数据任务的进一步回调,而是开始收到来自下载任务的回调。
9、在从服务器传输的过程中,代理会定时的收到任务的回调来报告传输的进度。
对于数据任务,会话使用他们收到的原始数据调用代理的方法
URLSession:dataTask:didReceiveData:
对于下载任务,会话使用成功写入磁盘的字节数调用代理的方法
URLSession:downloadTask:didWriteData:totalBytesWritten:totalBytesExpectedToWrite:
如果用户告诉APP暂停下载,通过调用
cancelByProducingResumeData:
方法取消任务。
最后,如果用户告诉APP继续下载,那么需要传递已经返回的resume数据给
downloadTaskWithResumeData:
方法或
downloadTaskWithResumeData:completionHandler:
方法来创建新的下载任务来继续下载。(回到第1步)。
10、对于数据任务,NSURLSession对象可调用
URLSession:dataTask:willCacheResponse:completionHandler:
方法。然后APP决定是否允许缓存。如果你没有实现这个方法,默认的方式是使用会话的配置对象中指定的缓存策略。
11、如果响应是多部分编码的,会话可再次调用代理的didReceiveResponse方法,然后不调用或者多次调用didReceiveData。如果这样的情况发生了,那么请转至步骤8(处理didReceiveResponse调用)。
12、如果下载任务成功完成,那么NSURLSession对象使用临时文件的位置调用任务的
URLSession:downloadTask:didFinishDownloadingToURL:
方法。APP必须在代理方法返回前,要么从这个文件中读取响应数据,要么把它移动到持久存储的位置。
13、当任务完成时,NSURLSession对象使用一个error对象或者nil(如果任务成功完成)调用代理的方法
URLSession:task:didCompleteWithError:
如果下载任务继续,NSError对象的userInfo字典包含了NSURLSessionDownloadTaskResumeData 键的值。APP传递这个值来调用方法
downloadTaskWithResumeData:
或方法
downloadTaskWithResumeData:completionHandler:
来创建新的下载任务来继续存在的下载。
如果任务没有被继续,APP就会创建一个新的下载任务并从开始重启事件。
这两种情况下,如果传输失败,如果不是服务器原因,请转至步骤3(创建和继续任务)。
14、如果不再需要会话,我们可以通过调用invalidateAndCancel(取消任务)或finishTasksAndInvalidate (允许任务来在废弃之前完成)。
如果没有废弃会话,当APP终止时,它会自动消失(除非是具有活动任务的后台会话)。
在废弃会话后,当所有的任务被取消或完成时,会话会调用代理的URLSession:didBecomeInvalidWithError:方法。
当代理方法返回时,会话释放代理的强引用。
如果APP取消了正在进行的下载,虽然会发生错误,NSURLSession对象还是会调用代理的 URLSession:task:didCompleteWithError:方法。
线程安全
URL会话的API都是完全线程安全的。可任意创建会话和任务。代理方法调用完成处理回调时,会在代理队列中被自动适当安排。
NSCopying
会话和任务都遵守NSCopying协议,当copy一个会话或者任务时,我们会得到一个相同对象。而当copy一个配置对象时,我们会得到一个新的对象,可以独立的修改。
App Transport Security (ATS)应用传输安全
在iOS9.0和 OS X10.11开始出现,对于使用NSURLSession的所有HTTP连接,默认会启用这个叫做ATS的新安全功能。ATS要求HTTP连接使用HTTPS(RFC 2818)。
不同会话方式和不同任务类型的请求示例
1、单例会话
使用Block来处理请求
(1)、Data任务
//1、创建单例会话
NSURLSession *session = [NSURLSession sharedSession];
//2、创建请求和任务对象
NSURL *url = [NSURL URLWithString:@"https://www.jianshu.com/u/8ca9e2a2536a"];
NSURLSessionDataTask *dataTask = [session dataTaskWithURL:url completionHandler:^(NSData *data, NSURLResponse *response, NSError *error){
if (error == nil && data)
{
NSString *dataStr = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(@"请求成功 = %@", dataStr);
}
else
{
NSLog(@"请求失败");
}
}];
[dataTask resume];
(2)、download任务
//1、创建单例会话
NSURLSession *session = [NSURLSession sharedSession];
//2、创建请求和任务对象
NSURL *url = [NSURL URLWithString:@"https://image.baidu.com/search/detail?ct=503316480&z=0&ipn=d&word=%E5%9B%BE%E7%89%87&hs=0&pn=0&spn=0&di=113313207810&pi=0&rn=1&tn=baiduimagedetail&is=0%2C0&ie=utf-8&oe=utf-8&cl=2&lm=-1&cs=594559231%2C2167829292&os=2394225117%2C7942915&simid=3436308227%2C304878115&adpicid=0&lpn=0&ln=30&fr=ala&fm=&sme=&cg=&bdtype=0&oriquery=&objurl=http%3A%2F%2Fimg.taopic.com%2Fuploads%2Fallimg%2F120727%2F201995-120HG1030762.jpg&fromurl=ippr_z2C%24qAzdH3FAzdH3Fooo_z%26e3Bpw5rtv_z%26e3Bv54AzdH3Fejvp56AzdH3Fda8da0AzdH3Fdanll9_z%26e3Bip4s&gsm=0&islist=&querylist="];
NSURLSessionDownloadTask *downloadTask = [session downloadTaskWithURL:url completionHandler:^(NSURL *location, NSURLResponse *response, NSError *error){
if (error == nil && location)
{
NSLog(@"下载成功:location.path = %@", location.path);
NSString *filePath = @"/Users/shiru/Desktop/downloadImage.png";
NSError *fileError;
[[NSFileManager defaultManager] copyItemAtPath:location.path toPath:filePath error:&fileError];
if (fileError == nil) {
NSLog(@"file save success");
} else {
NSLog(@"file save error: %@",fileError);
}
}
else
{
NSLog(@"下载失败error");
}
}];
[downloadTask resume];
(3)、upload任务
//1、创建单例会话
NSURLSession *session = [NSURLSession sharedSession];
//2、创建请求和任务对象
NSURL *url = [NSURL URLWithString:@"https://www.freeimagehosting.net/upl.php"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
request.HTTPMethod = @"POST";
NSData *data = [NSData dataWithContentsOfFile:@"/Users/shiru/Desktop/private/个人相关/天籁小学.jpg"];
NSURLSessionUploadTask *uploadTask = [session uploadTaskWithRequest:request fromData:data completionHandler:^(NSData *data, NSURLResponse *response, NSError *error){
if (error == nil && data)
{
NSString *dataStr = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(@"上传成功:dataStr = %@", dataStr);
}
else
{
NSLog(@"上传失败");
}
}];
[uploadTask resume];
2、默认会话
####(1)、Data任务
在这里使用NSURLSessionDataDelegate代理的方法来处理请求
{
//1、创建会话配置
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
configuration.allowsCellularAccess = NO;
configuration.timeoutIntervalForRequest = 10;
//2、创建单例会话
NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration delegate:self delegateQueue:[NSOperationQueue mainQueue]];
//3、创建请求和任务对象
NSURL *url = [NSURL URLWithString:@"https://www.jianshu.com/u/8ca9e2a2536a"];
NSURLSessionDataTask *dataTask = [session dataTaskWithURL:url];
[dataTask resume];
}
#pragma mark -NSURLSessionDataDelegate
//接收到服务器响应
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask
didReceiveResponse:(NSURLResponse *)response
completionHandler:(void (^)(NSURLSessionResponseDisposition disposition))completionHandler
{
completionHandler(NSURLSessionResponseAllow);// 允许处理服务器的响应,才会继续接收服务器返回的数据
}
//接收服务器回传的数据,有可能执行多次
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask
didReceiveData:(NSData *)data
{
if (data)
{
NSString *dataStr = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(@"请求成功 = %@", dataStr);
}
else
{
NSLog(@"请求失败");
}
}
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask
willCacheResponse:(NSCachedURLResponse *)proposedResponse
completionHandler:(void (^)(NSCachedURLResponse * _Nullable cachedResponse))completionHandler
{
}
(2)、download任务
{
//1、创建会话配置
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
configuration.allowsCellularAccess = NO;
configuration.timeoutIntervalForRequest = 10;
//2、创建单例会话
NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration delegate:self delegateQueue:[NSOperationQueue mainQueue]];
//3、创建请求和任务对象
NSURL *url = [NSURL URLWithString:@"https://www.jianshu.com/u/8ca9e2a2536a"];
NSURLSessionDownloadTask *downloadTask = [session downloadTaskWithURL:url];
[downloadTask resume];
}
#pragma mark -NSURLSessionDownloadDelegate
//下载完成
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask
didFinishDownloadingToURL:(NSURL *)location
{
if (location)
{
NSLog(@"下载成功:location.path = %@", location.path);
NSString *filePath = @"/Users/shiru/Desktop/downloadImage1.png";
NSError *fileError;
[[NSFileManager defaultManager] copyItemAtPath:location.path toPath:filePath error:&fileError];
if (fileError == nil) {
NSLog(@"file save success");
} else {
NSLog(@"file save error: %@",fileError);
}
}
else
{
NSLog(@"下载失败error");
}
}
/*
监测临时文件下载的数据大小,当每次写入临时文件时,就会调用一次
bytesWritten 每次写入多少
totalBytesWritten 已经写入了多少
totalBytesExpectedToWrite 文件总大小
*/
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask
didWriteData:(int64_t)bytesWritten
totalBytesWritten:(int64_t)totalBytesWritten
totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite
{
//打印下载进度
NSLog(@"%f",totalBytesWritten * 1.0 / totalBytesExpectedToWrite);
}
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask
didResumeAtOffset:(int64_t)fileOffset
expectedTotalBytes:(int64_t)expectedTotalBytes
{
}
(3)、upload任务
//1、创建会话配置
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
configuration.allowsCellularAccess = NO;
configuration.timeoutIntervalForRequest = 10;
//2、创建单例会话
NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration delegate:self delegateQueue:[NSOperationQueue mainQueue]];
//3、创建请求和任务对象
NSURL *url = [NSURL URLWithString:@"https://www.freeimagehosting.net/upl.php"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
request.HTTPMethod = @"POST";
NSData *data = [NSData dataWithContentsOfFile:@"/Users/shiru/Desktop/private/个人相关/天籁小学.jpg"];
NSURLSessionUploadTask *uploadTask = [session uploadTaskWithRequest:request fromData:data completionHandler:^(NSData *data, NSURLResponse *response, NSError *error){
if (error == nil && data)
{
NSString *dataStr = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(@"上传成功:dataStr = %@", dataStr);
}
else
{
NSLog(@"上传失败");
}
}];
[uploadTask resume];
3、默认�会话实现断点续传
- (IBAction)startDonload:(id)sender
{
//1、创建会话配置
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
configuration.allowsCellularAccess = NO;
configuration.timeoutIntervalForRequest = 10;
//2、创建单例会话
NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration delegate:self delegateQueue:[NSOperationQueue mainQueue]];
self.session = session;
//3、创建请求和任务对象
NSURL *url = [NSURL URLWithString:@"https://120.25.226.186:32812/resources/videos/minion_02.mp4"];
NSURLSessionDownloadTask *downloadTask = [session downloadTaskWithURL:url];
self.downloadTask = downloadTask;
[self.downloadTask resume];
}
- (IBAction)pauseDownload:(id)sender
{
[self.downloadTask cancelByProducingResumeData:^(NSData *resumeData){
//将已下载的数据保存起来,以备断点续传使用
self.resumeData = resumeData;
}];
}
- (IBAction)resumeDownload:(id)sender
{
self.downloadTask = [self.session downloadTaskWithResumeData:self.resumeData];
[self.downloadTask resume];
}
#pragma mark -NSURLSessionDownloadDelegate
//下载完成
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask
didFinishDownloadingToURL:(NSURL *)location
{
if (location)
{
NSLog(@"下载成功:location.path = %@", location.path);
NSString *filePath = @"/Users/shiru/Desktop/downloadMP4File.mp4";
NSError *fileError;
[[NSFileManager defaultManager] copyItemAtPath:location.path toPath:filePath error:&fileError];
if (fileError == nil) {
NSLog(@"file save success");
} else {
NSLog(@"file save error: %@",fileError);
}
}
else
{
NSLog(@"下载失败error");
}
}
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask
didWriteData:(int64_t)bytesWritten
totalBytesWritten:(int64_t)totalBytesWritten
totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite
{
//打印下载百分比
NSLog(@"%f",totalBytesWritten * 1.0 / totalBytesExpectedToWrite);
}