简介
NSURLSession是苹果官方提供的一系列网络接口库,使用他们可以轻松实现下载和数据获取等任务。在上一篇文章中,我们介绍了使用NSURLConnection下载文件和断点续传的功能,实现起来比较麻烦,对于文件的操作也比较繁琐,如果使用NSURLSession,这一切都将变得极为容易。
用法
数据请求
1.获取URLSession单例对象,并利用该对象创建一个dataTask,使用结构体回调。
这段代码从网站上抓取JSON数组,解析为OC字典。NSURLSession *session = [NSURLSession sharedSession]; NSURLSessionDataTask *task = [session dataTaskWithURL:[NSURL URLWithString:@"http://www.soulghost.com/randompk/storeTest/baseRandom.php?type=attack"] completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableLeaves error:nil]; NSLog(@"%@",dict); }];
2.开启任务
所有任务在创建时都是暂停的,应该手动启动。[task resume];
小文件下载
1.获取URLSession单例对象,创建一个downloadTask。- 注意此任务默认将文件下载到tmp文件夹,并且在下载结束后如果不处理会秒删,一般的做法是把它移动到Document或者Caches中,当下载结束后会调用结构体,在结构体里处理文件即可。
通过NSFileManager可以实现文件的复制、移动操作,回调的location是tmp中刚刚下载的文件的URL。
NSURLSession *session = [NSURLSession sharedSession]; NSURLSessionDownloadTask *task = [session downloadTaskWithURL:[NSURL URLWithString:@"http://127.0.0.1/lesson1/nav.dmg"] completionHandler:^(NSURL *location, NSURLResponse *response, NSError *error) { // 临时下载到tmp,必须及时处理,否则会被系统秒删。 // 应该将临时文件移动到Caches文件夹 NSString *path = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject]; // 可以使用建议的文件名,与服务端一致 NSString *file = [path stringByAppendingPathComponent:response.suggestedFilename]; // 移动文件 NSFileManager *mgr = [NSFileManager defaultManager]; [mgr moveItemAtPath:location.path toPath:file error:nil]; }];
2.开启任务
所有任务在创建时都是暂停的,应该手动启动。[task resume];
大文件下载
大文件常常需要获取进度,这就需要设置代理,而不是用block回调。
1.遵循代理方法,创建两个成员,一个用于指向下载任务对象,另一个用于保存断点数据。@interface ViewController () <NSURLSessionDownloadDelegate> @property (nonatomic, strong) NSURLSessionDownloadTask *task; @property (nonatomic, strong) NSData *resumeData; @end
2.获取URLSession单例,创建下载任务,注意使用的方法与前面不同。
- 不要忘了保存task。
NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:[NSOperationQueue mainQueue]]; NSURLSessionDownloadTask *task = [session downloadTaskWithURL:[NSURL URLWithString:@"http://127.0.0.1/lesson1/nav.dmg"] ]; [task resume]; _task = task;
3.下载过程中会调用下面的代理方法,指示此次下载的字节数,一共下载的字节数与总字节数。
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite{ NSLog(@"写入量:%lld 下载进度:%f",bytesWritten,(double)totalBytesWritten/totalBytesExpectedToWrite); }
4.下载结束后回调用下面的代理方法,从中同样要移动文件,只是如果要想拿到响应体response的suggestedFilename,需要通过downloadTask。
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location{ NSString *path = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject]; // 可以使用建议的文件名,与服务端一致 NSString *file = [path stringByAppendingPathComponent:downloadTask.response.suggestedFilename]; // 移动文件 NSFileManager *mgr = [NSFileManager defaultManager]; [mgr moveItemAtPath:location.path toPath:file error:nil]; [self.btn setTitle:@"Start" forState:UIControlStateNormal]; }
5.如果要暂停下载,调用下面的方法,通过回调结构体拿到断点数据,保存在我们之前创建的成员中以便恢复。
- 注意用weakSelf避免循环引用。
- 任务结束后就无效了,应该让指针指向nil来释放内存。
__weak typeof(self) weakSelf = self; [self.task cancelByProducingResumeData:^(NSData *resumeData) { // resumeData内部包含了下次继续下载的开始位置 weakSelf.resumeData = resumeData; weakSelf.task = nil; }];
6.要恢复下载数据很容易,只需要通过断点创建任务即可。
- 注意清空resumeData。
NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:[NSOperationQueue mainQueue]]; // 传入上次暂停下载返回的数据 NSURLSessionDownloadTask *task = [session downloadTaskWithResumeData:self.resumeData]; [task resume]; _task = task; _resumeData = nil;
断点续传开始时会调用下面的代理方法说明文件信息。
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didResumeAtOffset:(int64_t)fileOffset expectedTotalBytes:(int64_t)expectedTotalBytes{ }