NSURLSession 初探

最近需要用到下载,并显示下载进度,于是一阵苦搜,找到NSURLSession可以实现这个功能,心中不免大喜!当然,用AFNetworking也能实现,但是NSURLSession也是要了解的啊!

NSURLSession的三个代表

提到NSURLSession,最先要了解的就是NSURLSession的三个Task:NSURLSessionDataTask、NSURLSessionDownloadTask和NSURLSessionUploadTask。

  • DataTask
    DataTask向服务器请求一个资源,然后将服务器返回的数据存储在内存中的一个或多个NSData对象中。DataTask只用于短暂数据的交互,并不支持后台工作。
  • Upload Task
    Upload Task类似于data tasks,它添加请求体的方法很简单,并可以让你在收到服务器反馈之前上传数据。还有一点,upload task支持后台工作。
  • Download Task
    Download Task直接将资源下载到外存中(disk),并支持任何工作方式(前台、后台、断点续传、取消或暂停,甚至是应用退出后继续工作)。

使用DataTask

- (void)viewDidLoad
{
    [super viewDidLoad];

    NSURLSession *session = [NSURLSession sharedSession];
    NSURLSessionDataTask *dataTask = [session dataTaskWithURL: [NSURL URLWithString:@"Your URL"] 
        completionHandler:^(NSData *data, NSURLResponse *response, NSError *error){
        //Your code
        }];
    [dataTask resume];
}

如果不是特别需要,使用sharedSession就可以获取NSURLSession的实例。在completionHandler中处理服务器返回的数据。默认情况下,建立的task会被挂起(NSURLSessionTaskStateXXXXX标识了任务状态),需要手动调用resume来启动任务。

使用Download Task

  • 前台下载
NSURLSessionConfiguration *sessionConfig = [NSURLSessionConfiguration defaultSessionConfiguration];
    NSURLSession *session = [NSURLSession sessionWithConfiguration:sessionConfig delegate:self delegateQueue:nil];
    NSURLSessionDownloadTask *downloadTask = [session downloadTaskWithURL:[NSURL URLWithString:@"Your URL"]];
    [downloadTask resume];

 - (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask
didFinishDownloadingToURL:(NSURL *)location
{
    NSData *data = [NSData dataWithContentsOfURL:location];

    //Your code

    [session finishTasksAndInvalidate];
}

 - (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask
      didWriteData:(int64_t)bytesWritten
 totalBytesWritten:(int64_t)totalBytesWritten
totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite
{
    float progress = totalBytesWritten/ totalBytesExpectedToWrite;

    dispatch_async(dispatch_get_main_queue(), ^{
        self.progressView.progress = progress;
    });
}

 - (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask
 didResumeAtOffset:(int64_t)fileOffset
expectedTotalBytes:(int64_t)expectedTotalBytes
{

}

需要获取下载进度时,要实现NSURLSessionDownloadDelegate。在这里,我用defaultSessionconfiguration来创建一个session,并指定delegateQueue为nil,默认是串行队列(苹果提供了三个工厂来创建配置,除了我用到的默认配置外,还有ephemeralSessionConfiguration临时配置和backgroundSessionConfiguration后台配置)。创建完download task后,还是需要手动调用resume方法来启动下载。didFinishDownloadingToURL函数是下载完成后处理数据的,通过给出的URL能获得下载好的数据。在完成数据处理后,不使用session的话需要手动释放session,调用finishTasksAndInvalidate即可。didWriteData函数可以用来记录下载进度,在主线程中可以根据这个进度来更新Progress。didResumeAtOffset函数是在恢复下载时调用。

  • 后台下载
    1.创建后台session, 随后使用这个session创建下载,并启动即可。
 - (NSURLSession *)createBackgroundSession
{
    static NSURLSession *session = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        NSURLSessionConfiguration *sessionConfiguration = [NSURLSessionConfiguration backgroundSessionConfiguration:@"<font color=#A52A2A>Your Idntification</font>"];
        session = [NSURLSession sessionWithConfiguration:sessionConfiguration delegate:self delegateQueue:nil];
    });
    return session;
}
  • 取消下载
-(IBAction)cancel:(id)sender
{
    if(!self.downloadTask)
        return;

    [self.downloadTask cancelByProducingResumeData:(^NSData *resumeData){
        if(!resumeData) 
            return;
        [self setResumeData:resumeData];
        [self setDownloadTask:nil];
    }];
}

如果要取消的下载的resumeData非空,我们还是把数据保存到视图控制器的resumeData属性中。

  • 恢复下载
- (IBaction)resume:(id)sender
{
    if(!self.resumeData) return;

    self.downloadTask = [self.session downloadTaskWithResumeData:self.resumeData];
    [self.downloadTask resume];
    [self setResumeData:nil];
}

我们先检查视图控制器中的resumeData是否有效,然后创建一个新的下载任务,传入resumeData。这个resumeData包含了所有session需要重新创建下载任务的信息,然后调用resume通知下载任务开始,并置视图控制器的resumeData为空。

  • 在App退出后下载完成时通知操作系统

    1 .在AppDelegate头文件中加入一个函数类型

#import <UIKit/UIKit.h>

@interface AppDelegate : UIResponder <UIApplicationDelegate>

@property (strong, nonatomic) UIWindow *window;

@property (copy, nonatomic) void (^backgroundSessionCompletionHandler)();

@end

2 . 在AppDelegate的m文件中重写handleEventsForBackgroundURLSession函数,设置block

- (void)application:(UIApplication *)application handleEventsForBackgroundURLSession:(NSString *)identifier completionHandler:(void (^)())completionHandler
{
    [self setBackgroundSessionCompletionHandler:completionHandler];
}

3 . 在didFinishDownloadingToURL方法中调用我们自己写的下载完成后通知操作系统的方法

- (void)invokeBackgroundSessionCompletionHandler
{
    [self.session getTasksWithCompletionHandler:^(NSArray *dataTasks, NSArray *uploadTasks, NSArray *downloadTasks){
        NSUinteger count = [dataTasks count] + [uploadTasks count] + [downloadTasks count];

        if(!count){
           AppDelegate *delegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
           void(^backgroundSessionCompletionHandler)() = [delegate backgroundSessionCompletionHandler];

           if(backgroundSessionCompletionHandler){
               [delegate setBackgroundSessionCompletionHandler:nil];
               backgroundSessionCompletionHandler();
           }
        }
    }];
}

猜你喜欢

转载自blog.csdn.net/koptop/article/details/51407042
今日推荐