ios NSURLSession的应用

NSURLSession中task类型由三样东西决定:session的类型,任务的类型,任务在创建时app是否处于前台

1:session的类型分为

(1)Default Sessions ,与NSURLConnection差不多,使用基于硬盘的初级化缓存机制,并且存储凭证在用户钥匙串中
(2)Ephemeral Sessions 不存储任何数据到用户硬盘中,所有的缓存、凭证等都存储在内存中。比如浏览器无痕浏览等功能就可以基于这个来做。
(3)Background Sessions后台会话,相比默认会话,该会话会在后台开启一个线程进行网络数据处理。创建一个可以在后台甚至APP已经关闭的时候仍然在传输数据的会话。注意,后台Session一定要在创建的时候赋予一个唯一的identifier,这 样在APP下次运行的时候,能够根据identifier来进行相关的区分。如果用户关闭了APP,IOS 系统会关闭所有的background Session。而且,被用户强制关闭了以后,IOS系统不会主动唤醒APP,只有用户下次启动了APP,数据传输才会继续。

2:task(任务)的类型

(1)datatask :发送和接收数据都适用NSData对象,Data tasks 主要用于小的,常与服务器交互的数据。
(2)Download tasks:以一个文件的形式下载数据,可以后台下载(当session的类型不为Background sessions时,当App进入后台时下载是不能正常进行的,需要进行处理一下,但是session类型为Background sessions时,则程序在进入后台时不需要处理既还能正常下载)

(3)Upload tasks:以一个文件的形式上传数据,能后台上传(当session的类型不为Background sessions时,当App进入后台时下载是不能正常进行的,需要进行处理一下,但是session类型为Background sessions时,则程序在进入后台时不需要处理既还能正常下载)

3:  后台传输

当app处于suspend状态时,NSURLSession能提供后台传输,但是后台传输仅仅被由backgroundsessionconfiguration创建的session提供。后台传输实际上是由操作系统提供的一个单独的线程中执行。当你的app处于后台时,重新启动你的app的代价是昂贵的,对于后台传输导致了以下的一些限制:

(1)session必须为每一个任务提供一个delegate

(2)只有http和https协议被支持

(3)上传任务只支持文件上传,当程序退出时,上传data对象或者stream将会失败

(4)如果一个后台传输任务被初始化在程序处于后台时,session的configuration对象的discretionary(一个boolean值,决定后台任务可以被执行在系统的最佳性能下,例如:当你传输大量数据时,系统可能延迟任务至设备处于Wi-Fi网络下,如果这个属性设置成yes,系统将不会延迟执行)应该被设置为yes

创建一个NSURLSession,系统提供了两个创建方法:

sessionWithConfiguration:

sessionWithConfiguration:delegate:delegateQueue:

第一个根据创建的Configuration创建一个Session,系统默认创建一个新的OperationQueue处理Session的消息。

第二个可以设定回调的delegate(注意这个回调delegate会被强引用),并且可以设定delegate在哪个OperationQueue回调,如果我们将其设置为[NSOperationQueue mainQueue]就能在主线程进行回调非常的方便。

创建一个Task时系统提供了好几个方法,其中方法

downloadTaskWithURL:completionHandler:
<pre name="code" class="objc">downloadTaskWithURL

 这两种方法虽然表面上看只缺少一个下载完成回调block,但实际上却关系到session的delegate是否有用上面,第一种方法已经有了下载完成回调方法,所以即使session设置了delegate,系统也默认其delegate相应方法不起作用。所以想在session的delegate中实现一些功能,则选择第二种初始化方法。 

创建下载任务示例

#import "ViewController.h"

@interface ViewController ()<NSURLSessionDownloadDelegate>
@property (weak, nonatomic) IBOutlet UIProgressView *progressVi;
@property (weak, nonatomic) IBOutlet UIButton *downLoad;
@property(nonatomic,strong) NSURLSession *session;
@property (weak, nonatomic) IBOutlet UILabel *successLabel;
@property(nonatomic,strong) NSURLSessionDownloadTask *downLoadTask;
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    self.successLabel.hidden=YES;
   }

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    
}
- (IBAction)downloadClick:(id)sender {
    self.progressVi.hidden=NO;
    self.successLabel.hidden=YES;
    NSURLSession *session=[NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:nil];
    //不能用这个便利方法,这个方法session的delegate将不起作用
    //_downLoadTask=[session downloadTaskWithURL:[NSURL URLWithString:@""] completionHandler:^(NSURL * _Nullable location, NSURLResponse * _Nullable response, NSError * _Nullable error) {
        
   // }];
    _downLoadTask=[session downloadTaskWithURL:[NSURL URLWithString:@""]];
    [self.downLoadTask resume];
}
- (IBAction)stopClick:(id)sender {
    [self.downLoadTask suspend];
}
- (IBAction)cancelClick:(id)sender {
    [self.downLoadTask cancel];

}
- (IBAction)resumeClick:(id)sender {
    [self.downLoadTask resume];
}
#pragma mark delegate
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask
      didWriteData:(int64_t)bytesWritten
 totalBytesWritten:(int64_t)totalBytesWritten
totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite{

    //在另一个线程中进行的,不是主线程,即下载任务不是在主线程中进行,更新ui需在主线程中进行
//如果[NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:nil]中
//delegateQueue为主队列,则不需要切回主线程
 dispatch_async(dispatch_get_main_queue(), ^{
         self.progressVi.progress=(float)totalBytesWritten/totalBytesExpectedToWrite;
    });
   
}
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask
didFinishDownloadingToURL:(NSURL *)location{
    //更新ui在主线程
    [self performSelectorOnMainThread:@selector(updateUI) withObject:nil waitUntilDone:NO];
     NSLog(@"%@",[NSThread currentThread]);
}
-(void)updateUI{
    self.successLabel.hidden=NO;
    self.progressVi.hidden=YES;
}
@end

session与ApplicationDelegate交互

在ios中,当一个后台传输完成或者需要凭证时,如果你的app处于后台时,ios在后台自动重登app,调用delegate的application:handleEventsForBackgroundURLSession:completionHandler: 方法,在app的app的applicationdelegate中应该存储这个completionHandler,当由同一个session创建的task都完成时,系统发送一个URLSessionDidFinishEventsForBackgroundURLSession:消息给session代理,session delegate应该调用刚存储的completionHandler对象
代码示例:
//application delegate方法
-(void) application:(UIApplication *)application handleEventsForBackgroundURLSession:(NSString *)identifier completionHandler:(void (^)())completionHandler{
    self.completionHandler=completionHandler;
}
//session代理方法
 -(void)URLSessionDidFinishEventsForBackgroundURLSession:(NSURLSession *)session{
    AppDelegate *delegate=(AppDelegate *)[[UIApplication sharedApplication] delegate];
    //...可以更新ui
    if(delegate.completionHandler){
        void (^completionHandler) ()=delegate.completionHandler;
        delegate.completionHandler=nil;
        //Because the provided completion handler is part of UIKit, you must call it on your main thread. For example:
        [[NSOperationQueue mainQueue] addOperationWithBlock:^{
            completionHandler();//通知delegate代理更新ui
        }];
    }
}

参考文档:http://www.cnblogs.com/kenshincui/p/4042190.html#NSURLSession
                  http://www.cocoachina.com/industry/20131106/7304.html



  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值