iOS 网络请求--原生网络类

平时在项目中一直是用网络请求的第三方框架 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);

}

推荐阅读更多精彩内容