现在越来越多的开发习惯于使用各种第三方框架,诚然,第三方框架给我们开发带来了很多便利,但我们不能太依赖于第三方,在使用第三方的同时学习其原理才是硬道理。

所以今天我们就来讲讲AFNetworking所使用的NSURLSession相关的知识。

NSURLSession 有几个优势:

1支持HTTP2.0协议

2在处理下载任务的时候可以直接把数据下载到磁盘

3支持后台下载上传

4同一个session发送多个请求,只需要建立一次连接(复用了TCP)

5多线程异步处理,效率更高

要了解NSURLSession的使用,我们可以先来看看相关的几个类

NSURLSessionTask 是抽象类, 我们不能直接使用,只能使用其子类。

NSURLSessionTask 有三个个子类,NSURLSessionDataTask,NSURLDownloadTask 和NSURLStreamTask,  其中NSURLDownloadTask对下载做了优化,会写到缓存中,避免内存暴涨的问题。 NSURLSessionDataTask 有一个子类,NSURLUploadTask。继承关系如下:

接下来我们来熟悉一下NSURLSession的使用,

1:  创建NSURLSession(也可以直接使用系统提供的单例方法)

2:创建NSURLSessionTask

3:开始请求

NSURLRequest相信大家都比较熟悉,通过NSURLRequest和NSURLSessionDataTask我们可以直接发起GET或者POST请求

NSURLSessionc除了单例之外,有两个对象的获取方法

+ (NSURLSession *)sessionWithConfiguration:(NSURLSessionConfiguration *)configuration;

+ (NSURLSession *)sessionWithConfiguration:(NSURLSessionConfiguration *)configuration delegate:(nullable id <NSURLSessionDelegate>)delegate delegateQueue:(nullable NSOperationQueue *)queue;

其中,两个方法中都使用到了NSURLSessionConfiguration, 这里主要配置一些缓存,超时的规则,大多数情况下我们只要使用默认的配置就好了。

第二个方法我们看到初始化时候使用到了代理和NSOperationQueue, 当不设置代理时,我们只能在dataTask的block中做处理,但如果我们要获取下载进度之类的信息时,必须使用代理。此外,传入的NSOperationQueue可以让我们指定任务所在的队列,限制并发的任务数等。

接下来我们要创建NSURLSessionTask(只能使用其子类)。 我们先来看看其相关属性。

@property (readonly)                 NSUInteger    taskIdentifier;    /* an identifier for this task, assigned by and unique to the owning session */ 任务标记
@property (nullable, readonly, copy) NSURLRequest *originalRequest; /* may be nil if this is a stream task */ 原始请求
@property (nullable, readonly, copy) NSURLRequest *currentRequest; /* may differ from originalRequest due to http server redirection */ 现在的请求,可能被重定向
@property (nullable, readonly, copy) NSURLResponse *response; /* may be nil if no response has been received */ 进度 /*
* NSProgress object which represents the task progress.
* It can be used for task progress tracking.
*/
@property (readonly, strong) NSProgress *progress API_AVAILABLE(macos(10.13), ios(11.0), watchos(4.0), tvos(11.0));

在通过NSURLSession来获取NSURLSessionTask时要使用NSURLRequest或者USURL来进行初始化,下面以获取NSURLDataTask为例

/* Creates a data task with the given request.  The request may have a body stream. */
- (NSURLSessionDataTask *)dataTaskWithRequest:(NSURLRequest *)request; /* Creates a data task to retrieve the contents of the given URL. */
- (NSURLSessionDataTask *)dataTaskWithURL:(NSURL *)url;

直接传入url或默认为get方法,如果需要修改需要使用NSMutuableURLRequest

我们来看看一次完整的请求

 NSURL *url = [NSURL URLWithString:@"https://www.baidu.com"];
NSMutableURLRequest *req = [NSMutableURLRequest requestWithURL:url];
req.HTTPMethod = @"GET"; //修改http 方法
//创建session,可以传入代理和处理的队列,代理方法不再一一列出
NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:nil delegateQueue:nil];
//创建任务
NSURLSessionDataTask *task = [session dataTaskWithRequest:req completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
//请求结束,进行处理 }]; [task resume]; //开始任务

当然,回调方法比较简单,很多时候并不能满足我们的需求,这时候就需要使用代理了。需要注意的时,NSURLSession会对代理对象强引用,因此需要在适当的时候进行释放。

以下是几个常用的代理方法:

- (void)URLSession:(NSURLSession *)session
dataTask:(NSURLSessionDataTask *)dataTask
didReceiveResponse:(NSURLResponse *)response
completionHandler:(void (^)(NSURLSessionResponseDisposition disposition))completionHandler
{
////默认情况下不接收数据
//必须告诉系统是否接收服务器返回的数据
if (completionHandler) {
completionHandler(disposition);
}
} - (void)URLSession:(NSURLSession *)session
dataTask:(NSURLSessionDataTask *)dataTask
didReceiveData:(NSData *)data
{
//接收到返回数据时调用,可能调用多次 } -(void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error { //请求完成或者失败时调用 } //NSURLDownloadDelegate - (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
{ //下载接收到数据调用,可能调用多次
} - (void)URLSession:(NSURLSession *)session
downloadTask:(NSURLSessionDownloadTask *)downloadTask
didResumeAtOffset:(int64_t)fileOffset
expectedTotalBytes:(int64_t)expectedTotalBytes
{ //断点下载
}

创建NSURLSessionUploadTask 和 NSURLSessionDownloadTask以及NSURLStreamTask的使用方式类似。

但要注意一些特殊情况,NSURLSessionDownloadTask在下载完毕只有会被从缓存中清除,需要我们在代理方法中将其复制保存到其他地方。

- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask
didFinishDownloadingToURL:(NSURL *)location;

此外NSURLSessionDownload是支持断点重传的。

NSURLSessioNUploadSessionTask和NSURLSessionDataTask之间的区别并不大,只是可以直接传入需要上传的数据,不需要手动构建http请求。

/* Creates an upload task with the given request.  The body of the request will be created from the file referenced by fileURL */
- (NSURLSessionUploadTask *)uploadTaskWithRequest:(NSURLRequest *)request fromFile:(NSURL *)fileURL; /* Creates an upload task with the given request. The body of the request is provided from the bodyData. */
- (NSURLSessionUploadTask *)uploadTaskWithRequest:(NSURLRequest *)request fromData:(NSData *)bodyData; /* Creates an upload task with the given request. The previously set body stream of the request (if any) is ignored and the URLSession:task:needNewBodyStream: delegate will be called when the body payload is required. */
- (NSURLSessionUploadTask *)uploadTaskWithStreamedRequest:(NSURLRequest *)request;

NSURLStreamTask是进行流传输的,可以用来做视频流音频流,水平有限,具体实战还需摸索。

关于后台下载和上传:

NSURLSession是支持后台上传和下载的,而且用起来相当方便。以下载为例;

首先,创建NSURLSession时设置对应的cofigration,否则无法在后台执行。同时要对应的sessionID,这是为了后台下载完成时使用的。

NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:@"com.test.backGroudSession"]];

  

这样设置之后,我们的任务下载任务能在后台执行了,但是由于苹果的后台机制,当我们按下home键的时候,所有线程包括主线程的任务都会被挂起,NSURLSession的代理方法是不会走的,

如果想要正确的后台下载可以有两种方式:

1:申请后台执行时间

2:在appDelegate中实现相关的代理方法

这两种方式可以根据实际情况来选择,对于一些很重要的任务可以申请后台执行时间。

我们先来介绍一下如何申请后台执行时间:(3分钟,iOS7之前是10分钟)

 __block UIBackgroundTaskIdentifier bgTaskIdentifier;
bgTaskIdentifier = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
if (bgTaskIdentifier != UIBackgroundTaskInvalid) {
//结束所有后台任务
bgTaskIdentifier = UIBackgroundTaskInvalid;
} }];

申请后台执行时间只有这样一段代码,只要监听一下UIApplicationDidEnterBackgroundNotification在进入后台时申请就好了

需要注意的是,在后台执行时间结束前必须结束任务,否则会被系统回收。有时候有些异步操作在结束回调中执行并不能保证在后台执行时间结束前停止,这时候可以通过

backgroundTimeRemaining 属性来判断何时结束
[UIApplication sharedApplication].backgroundTimeRemaining 

接下来介绍一下实现appDelegate相关方法的方式,在进入后台时,NRULSessionDelegate相关的方法是不会走的,但是在下载完成的时候,会在

AppDelegate中回调。

首先在Appdelegate中实现回调,保存回调方法,当然如果有多个session在后台下载,可以根据identifier进行区分保存。

- (void)application:(UIApplication *)application handleEventsForBackgroundURLSession:(NSString *)identifier completionHandler:(void (^)(void))completionHandler {

    //保存回调方法,后续需要使用
self.backGroundCompletionHandler = completionHandler; }

当应用进入前台时,此时会回调NSURLSessionDelegate相关的方法

- (void)URLSessionDidFinishEventsForBackgroundURLSession:(NSURLSession *)session
{
NSLog(@"所有后台任务已经完成"); if (session.configuration.identifier) {
// 执行实现保存的后台session回调
AppDelegate *delegate = (AppDelegate *)[UIApplication sharedApplication].delegate;
if (delegate.backGroundCompletionHandler) {
delegate.backGroundCompletionHandler();
}
}
}

  

当然,此时也会回调下载成功失败的相关回调,和正常下载时一样的。


NSURLSession使用, 后台下载的更多相关文章

  1. ios 后台下载,断点续传总结

    2018年12月05日 16:09:00 weixin_34101784 阅读数:5 https://blog.csdn.net/weixin_34101784/article/details/875 ...

  2. iOS12 中的后台下载与上传

    严格意义上来说,iOS并不能像Android一样,真的在后台开启一个下载Service,一直下载.但是它可以进行在系统允许范围内的后台上传和下载. 当使用 NSURLSessionConfigurat ...

  3. WP8.1 Study17:网络之后台下载/上传及HttpClient

    一.后台下载/上传 1.简介 使用BackgroundTransferGroup可以十分方便操作上传及下载文件,BackgroundDownloader和BackgroundUploader类中的方法 ...

  4. 背水一战 Windows 10 (119) - 后台任务: 后台下载任务(任务分组,组完成后触发后台任务)

    [源码下载] 背水一战 Windows 10 (119) - 后台任务: 后台下载任务(任务分组,组完成后触发后台任务) 作者:webabcd 介绍背水一战 Windows 10 之 后台任务 后台下 ...

  5. 背水一战 Windows 10 (118) - 后台任务: 后台下载任务(任务分组,并行或串行执行,组完成后通知)

    [源码下载] 背水一战 Windows 10 (118) - 后台任务: 后台下载任务(任务分组,并行或串行执行,组完成后通知) 作者:webabcd 介绍背水一战 Windows 10 之 后台任务 ...

  6. 背水一战 Windows 10 (117) - 后台任务: 后台下载任务

    [源码下载] 背水一战 Windows 10 (117) - 后台任务: 后台下载任务 作者:webabcd 介绍背水一战 Windows 10 之 后台任务 后台下载任务 示例演示 uwp 的后台下 ...

  7. ios开发视频播放后台下载功能实现 :1,ios播放视频 ,包含基于AVPlayer播放器,2,实现下载,iOS后台下载(多任务同时下载,单任务下载,下载进度,下载百分比,文件大小,下载状态)(真机调试功能正常)

    ABBPlayerKit ios开发视频播放后台下载功能实现 : 代码下载地址:https://github.com/niexiaobo/ABBPlayerKit github资料学习和下载地址:ht ...

  8. 【Mac】nsurlsessiond 后台下载问题的解决方法

    最近在使用 Mac 系统的时候,经常发现 nsurlsessiond 这个进程,一直在后台下载,非常占用网速.解决方案如下: 通过终端执行下面的语句可以停止后台的自动更新: #!/bin/sh lau ...

  9. java-web调用后台下载方法

    后台下载指定文件必定会用到流, 无论使用poi还是使用jxl导出excel都需要用到流一种是outputstrean,另一种fileoutputstream第一种:如果想要弹出保存的提示框必须加入下列 ...

随机推荐

  1. MYSQL数据库学习八 触发器的操作

    8.1 触发器 在表发生更改时,自动进行一些处理.例如,学生表中每增加一条关于学生记录时,学生的总数就必须同时改变,同时需要检查电话号码格式是否正确,地址缩写是否正确. 以下语句会激活触发器: DEL ...

  2. 【Django】 rest-framework和RestfulAPI的设计

    [rest-framework] 这是一个基于django才能发挥作用的组件,专门用于构造API的. 说到API,之前在其他项目中我也做过一些小API,不过那些都是玩票性质,结构十分简单而且要求的设计 ...

  3. [poj1094]Sorting It All Out_拓扑排序

    Sorting It All Out poj-1094 题目大意:给出一些字符串之间的大小关系,问能否得到一个唯一的字符串序列,满足权值随下标递增. 注释:最多26个字母,均为大写. 想法:显然,很容 ...

  4. 分区表SQL调优/优化(Tuning)时容易“被欺骗”的场景之一

    近几天没有用户找到,除了看看书,就是上网浏览点东西,好不惬意.可惜好景不长,正在享受悠闲惬意的日子时,一个用户的工作人员QQ找到我,说他们在统计一些数据,但一个SQL特别慢,或者说就从来没出过数据,我 ...

  5. 一台windows主机上运行2个tomcat

    为了运行2个不同的项目,需要在一台机上运行2个tomcat,但是发现运行第二个tomcat时,总会加载第一个tomcat中的项目,也就是实际运行的是第一个tomcat 所以需要做如下配置: 1.修改第 ...

  6. 第二次作业-Steam软件分析

    1 .介绍产品相关信息 随着电子音频游戏产业的发展以及正版意识的崛起,Steam已经成为大部分游戏爱好者必备的一款游戏下载平台.这款软件也使得Valve公司从一个游戏制作公司成功扩展业务到一个承揽众多 ...

  7. spring mvc 整合Quartz

    Quartz是一个完全由java编写的开源作业调度框架.不要让作业调度这个术语吓着你.尽管Quartz框架整合了许多额外功能, 但就其简易形式看,你会发现它易用得简直让人受不了!Quartz整合在sp ...

  8. 学号:201621123032 《Java程序设计》第2周学习总结

    1: 本周学习总结 本周学习java的数据类型,两种数据类型:基本数据类型和引用数据类型. 学习关于String和StringBuilder之间不同. 本周还学习数组.一维数组,多维数组,和动态数组. ...

  9. JAVA中GridBagLayout布局管理器应用详解

    很多情况下,我们已经不需要通过编写代码来实现一个应用程序的图形界面,而是通过强大的IDE工具通过拖拽辅以简单的事件处理代码即可很轻松的完成.但是我们不得不面对这样操作存在的一些问题,有时候我们希望能够 ...

  10. Telnet、SSH和VNC 区别

    Telnet Telnet是进行远程登录的标准协议,它是当今Internet上应用最广泛的协议之一.它把用户正在使用的终 端或计算机变成网络某一远程主机的仿真终端,使得用户可以方便地使用远程主机上的软 ...