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交互
代码示例:
//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