IOS开发—网络请求、上传下载、断点续传(NSURLSession)

来源:互联网 发布:网络购物法律法规 编辑:程序博客网 时间:2024/04/28 04:56

简单说明

在iOS9.0之后,以前使用的NSURLConnection过期,苹果推荐使用NSURLSession来替换NSURLConnection完成网路请求相关操作。

NSURLSessionConfiguration类对网络请求层的设置选项进行了扩充,可以配置从指定可用网络,到 cookie,安全性,缓存策略,再到使用自定义协议,启动事件的设置,以及用于移动设备优化的几个新属性。本例只对常规的网络请求作演示,不涉及NSURLSessionConfiguration配置。

NSURLSession的使用非常简单,先根据会话对象创建一个请求Task,然后执行该Task即可。

本文介绍内容包括常规数据请求(GET/POST)、数据下载上传以及断点续传,仅贴出代码供参考。

数据请求(GET/POST)

//GET方式(系统默认)    NSString *urlString = @"http://kaiyi.3tichina.com:8001/mall/list.php?page=1&catid=4";    NSURL *url = [NSURL URLWithString:[urlString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];    NSURLRequest *request = [NSURLRequest requestWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:10.0f];    NSURLSession *session = [NSURLSession sharedSession];    NSURLSessionDataTask *task = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {        if (!error) {            NSDictionary *dic = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingAllowFragments error:nil];            NSLog(@"%@",dic);        }else{            NSLog(@"Error: %@",error.localizedDescription);        }    }];    [task resume];
//POST方式    NSString *urlString = @"http://kaiyi.3tichina.com:8001/mall/list.php";    NSURL *url = [NSURL URLWithString:urlString];    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:10.0f];    [request setHTTPMethod:@"POST"];    NSString *httpBodyString = @"page=1&catid=4";    [request setHTTPBody:[httpBodyString dataUsingEncoding:NSUTF8StringEncoding]];    NSURLSession *session = [NSURLSession sharedSession];    NSURLSessionDataTask *task = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {        if (!error) {            NSDictionary *dic = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingAllowFragments error:nil];            NSLog(@"%@",dic);        }else{            NSLog(@"Error: %@",error.localizedDescription);        }    }];    [task resume];

数据上传

    NSString *urlString = @"";/*目标服务器url*/    NSURL *url = [NSURL URLWithString:urlString];    NSURLRequest *request = [NSURLRequest requestWithURL:url];    NSURLSession *session = [NSURLSession sharedSession];    NSURLSessionUploadTask *uploadTask = [session uploadTaskWithRequest:request fromData:[NSData dataWithContentsOfFile:@""]/*要上传的数据*/ completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {        if (!error) {            //TODO: 上传成功的操作        }else{            NSLog(@"error: %@",error.localizedDescription);        }    }];    [uploadTask resume];

数据下载

    NSString *urlString = @"https://www.google.com.hk/images/branding/googlelogo/2x/googlelogo_color_272x92dp.png";    NSURL *url = [NSURL URLWithString:[urlString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];    NSURLRequest *request = [[NSURLRequest alloc]initWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:15.0];    NSURLSession *session = [NSURLSession sharedSession];    NSURLSessionDownloadTask *downloadTask = [session downloadTaskWithRequest:request completionHandler:^(NSURL * _Nullable location, NSURLResponse * _Nullable response, NSError * _Nullable error) {        if (!error) {            //将下载的临时数据移到本地持久化            NSString *docpath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];            NSString *filePath = [docpath stringByAppendingPathComponent:[[response URL] lastPathComponent]];            NSFileManager *fm = [NSFileManager defaultManager];            [fm moveItemAtURL:location toURL:[NSURL fileURLWithPath:filePath] error:nil];            dispatch_async(dispatch_get_main_queue(), ^{                //TODO: 更新UI                self.imageView.image = [UIImage imageWithData:[NSData dataWithContentsOfFile:filePath]];            });        }else{            NSLog(@"error: %@",error.localizedDescription);        }    }];    [downloadTask resume];

断点续传

演示demo界面如下:

@interface BreakpointContinuinglyViewController ()<NSURLSessionDownloadDelegate>@property (weak, nonatomic) IBOutlet UIProgressView *progress;@property (weak, nonatomic) IBOutlet UILabel *labelStatus;@property (weak, nonatomic) IBOutlet UIButton *buttonDownload;@property (weak, nonatomic) IBOutlet UIButton *buttonSuspend;@property (weak, nonatomic) IBOutlet UIButton *buttonResume;@property (nonatomic, strong) NSURLSession *session;@property (nonatomic, strong) NSURLSessionDownloadTask *downloadTask;@property (nonatomic, strong) NSData *resumeData;  //已下载数据@end@implementation BreakpointContinuinglyViewController- (void)viewDidLoad {    [super viewDidLoad];    // Do any additional setup after loading the view.    [self loadBaseUI];}- (void)didReceiveMemoryWarning {    [super didReceiveMemoryWarning];    // Dispose of any resources that can be recreated.}- (void)loadBaseUI{    self.progress.progress = 0.f;}- (IBAction)actionStartDownload:(id)sender {    NSString *sourcePath = @"http://www.1ting.com/api/audio?/i/1031/7/14.mp3";    NSURL *url = [NSURL URLWithString:sourcePath];    NSURLRequest *request = [NSURLRequest requestWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:5.f];    /*!     第一个参数为session的配置信息,[NSURLSessionConfiguration defaultSessionConfiguration]为默认配置     第二个参数为代理对象     第三个参数为队列,决定执行代理方法的线程。可以是主队列和自定义队列:     主队列[NSOperationQueue mainQueue] 下载完毕后如果需要根据下载数据操作UI通常放入主队列     自定义队列[NSOperationQueue alloc]init] 下载完毕后如果只是数据的操作通常放入自定义队列     */    _session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:[NSOperationQueue mainQueue]];    _downloadTask = [_session downloadTaskWithRequest:request];    [_downloadTask resume];    self.labelStatus.text = @"连接中...";}- (IBAction)actionSuspend:(id)sender {    /*暂停任务     暂停后超时计数器开始运作,若规定时间内没有resume任务,task运行失败,回调URLSession:task:didCompleteWithError:方法,通过该方法中的error参数可以获取到已经下载的数据     */    [_downloadTask suspend];    self.labelStatus.text = @"暂停下载";}- (IBAction)actionResume:(id)sender {    if (self.resumeData) {        //断点续传        _downloadTask = [_session downloadTaskWithResumeData:self.resumeData];    }    /*task在3中状态下都可以resume     1.task未开始,通过resume开始执行     2.task暂停,通过resume继续执行     3.通过已下载的数据继续执行task(断点续传)     */    [_downloadTask resume];    self.labelStatus.text = @"等待继续下载";}- (IBAction)actionCancel:(id)sender {    /*取消任务     暂停中的task同样可以取消     取消后立即回调URLSession:task:didCompleteWithError:方法。     */    [_downloadTask cancel];    //    [_downloadTask cancelByProducingResumeData:^(NSData * _Nullable resumeData) {    //        //因注意不要重复获取已下载的数据(要么这里获取,要么URLSession:task:didCompleteWithError:方法了获取)    //        self.resumeData = [NSData dataWithData:resumeData];    //    }];    self.labelStatus.text = @"任务已取消";}#pragma mark - NSURLSessionDownloadDelegate//监听下载过程- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask      didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWrittentotalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite{    //TODO: 判断是否连接成功    self.labelStatus.text = @"下载进行中";    self.progress.progress = (float)totalBytesWritten/totalBytesExpectedToWrite;}//完成下载(下载成功)- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTaskdidFinishDownloadingToURL:(NSURL *)location{    NSString *docPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject];    NSString *filePath = [docPath stringByAppendingPathComponent:@"14.mp3"];    NSFileManager *fm = [NSFileManager defaultManager];    [fm moveItemAtURL:location toURL:[NSURL fileURLWithPath:filePath] error:nil];    self.labelStatus.text = @"下载完成 数据已保存到本地";}//开始断点续传时调用- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didResumeAtOffset:(int64_t)fileOffsetexpectedTotalBytes:(int64_t)expectedTotalBytes{    NSLog(@"断点续传:%lld",fileOffset);}#pragma mark - NSURLSessionTaskDelegate//任务执行结束时调用,可能成功可能失败。若失败,可以通过NSURLSessionDownloadTaskResumeData作为key从error的userinfo中获取到已经下载的数据- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)taskdidCompleteWithError:(nullable NSError *)error{    if (error) {        self.resumeData = [error.userInfo objectForKey:NSURLSessionDownloadTaskResumeData];        NSLog(@"%@",error.localizedDescription);        self.labelStatus.text = @"下载失败,数据已保存";    }}@end

欢迎大家指错或者提出宝贵意见!!

参考文档:
《从 NSURLConnection 到 NSURLSession》
《NSURLSession 教程》
《iOS开发网络篇—发送GET和POST请求(使用NSURLSession)》

0 0