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

简单说明

在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)totalBytesWritten
totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite{
    //TODO: 判断是否连接成功
    self.labelStatus.text = @"下载进行中";
    self.progress.progress = (float)totalBytesWritten/totalBytesExpectedToWrite;
}

//完成下载(下载成功)
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask
didFinishDownloadingToURL:(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)fileOffset
expectedTotalBytes:(int64_t)expectedTotalBytes{
    NSLog(@"断点续传:%lld",fileOffset);
}

#pragma mark - NSURLSessionTaskDelegate
//任务执行结束时调用,可能成功可能失败。若失败,可以通过NSURLSessionDownloadTaskResumeData作为key从error的userinfo中获取到已经下载的数据
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task
didCompleteWithError:(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)》

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值