博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
IOS断点下载
阅读量:4982 次
发布时间:2019-06-12

本文共 6576 字,大约阅读时间需要 21 分钟。

下载的一些用法

①对于小文件,可以直接下载,无需断点下载等处理。

1 -(void)clickDownBtn{ 2     NSURL *url = [NSURL URLWithString:@"https://picjumbo.imgix.net/HNCK8461.jpg?q=40&w=1650&sharp=30"]; 3     if (self.imgView.image == nil) { 4         [self downLoad:url]; 5     }  6 } 7  8 //下载过程 9 -(void)downLoad:(NSURL *)url{10     dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{11         NSData *imgData = [NSData dataWithContentsOfURL:url];12         UIImage *img = [UIImage imageWithData:imgData];13         if (imgData != nil) {14             dispatch_sync(dispatch_get_main_queue(), ^{15                 self.imgView.image = img;16             });17         }18     });19 }

需要注意的是,多线程中,数据处理是在子线程,UI更新是在主线程。若处理数据时没有在子线程中进行,那么会发生线程阻塞、界面卡死的情况。如下载图片时,

-(void)downLoad:(NSURL *)url{    //数据处理(NSData)是在主线程中进行,所以会卡死    //况且这种写法是没有意义的,本来就在主线程,就无需再跳往主线程更新UI    NSData *imgData = [NSData dataWithContentsOfURL:url];    UIImage *img = [UIImage imageWithData:imgData];    if (imgData != nil) {        dispatch_sync(dispatch_get_main_queue(), ^{            self.imgView.image = img;        });    }}

正确的方法是,先开辟子线程,然后在主线程更新UI。

开辟子线程

-(void)downLoad:(NSURL *)url{    //开辟子线程    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{        //操作    });}

async是异步,sync是同步

 

②而对于大文件,则可以使用NSURLSession实现暂停、断点下载等操作。如下:

监听下载进度,需要实现代理NSURLSessionDownloadDelegate,在这代理中常用的有3个方法

/** 下载完毕会调用,location为文件临时地址 */-(void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location{    }
/** *  每次写入沙盒完毕后调用,在这里可以设置进度条数据等操作 *  totalBytesWritten/totalBytesExpectedToWrite,这两个用来监视下载进度 * *  @param bytesWritten              这次写入的大小 *  @param totalBytesWritten         已经写入沙盒的大小 *  @param totalBytesExpectedToWrite 文件总大小 */-(void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask               didWriteData:(int64_t)bytesWrittentotalBytesWritten:(int64_t)totalBytesWrittentotalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite{    }
/** 恢复下载时使用 */-(void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didResumeAtOffset:(int64_t)fileOffset expectedTotalBytes:(int64_t)expectedTotalBytes{    }

示例代码如下,在.m中

/** 展示进度的label */@property(nonatomic,strong) UILabel *progressLabel;/** 进度动画 */@property(nonatomic,strong) UIProgressView *progressView;/** 下载按钮 */@property(nonatomic,strong) UIButton *downBtn;/** 下载任务 */@property(nonatomic,strong) NSURLSessionDownloadTask *downLoadTask;/** 缓存数据 */@property(nonatomic,strong) NSData *tempData;/** session */@property(nonatomic,strong) NSURLSession *session;

session的懒加载为

-(NSURLSession *)session{    if (!_session) {        NSURLSessionConfiguration *cfg = [NSURLSessionConfiguration defaultSessionConfiguration];        _session = [NSURLSession sessionWithConfiguration:cfg delegate:self delegateQueue:[NSOperationQueue mainQueue]];    }    return _session;}

按钮点击事件如下:

//点击下载按钮-(void)clickDownBtn{    self.downBtn.selected = !self.downBtn.selected;    if (nil == self.downLoadTask) {        if (self.tempData) {            [self goOnDownload]; //继续下载        } else { //从0开始下载            [self startDownload];        }    } else {        [self pauseDownload];    }}/** 开始下载 */-(void)startDownload{    NSURL *url = [NSURL URLWithString:@"http://11.gxdx2.crsky.com/201501/apkok-v3.0.zip"];        //创建任务    self.downLoadTask = [self.session downloadTaskWithURL:url];    //开始任务    [self.downLoadTask resume];}/** 暂停下载 */-(void)pauseDownload{    //防止循环引用    __weak typeof(self) weakSelf = self;    [self.downLoadTask cancelByProducingResumeData:^(NSData *resumeData) {        //resumeData包含了继续下载的开始位置和url        weakSelf.tempData = resumeData;        weakSelf.downLoadTask = nil;    }];}/** 恢复下载 */-(void)goOnDownload{    //传入上次暂停下载返回的数据,即可恢复下载    self.downLoadTask = [self.session downloadTaskWithResumeData:self.tempData];    [self.downLoadTask resume];    self.tempData = nil;}

实现2个代理方法,第3个暂时用不到

/** 下载完毕会调用,location为文件临时地址 */-(void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location{    //选择下载文件路径,文件只能下载到该程序的目录中    //下边为下载到Documents文件夹,若将NSDocumentDirectory换为NSCachesDirectory,则会下载到Cache文件夹    NSString *caches = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];    //response.suggestedFilename建议使用的文件名,一般跟服务器端的名称一致    NSString *file = [caches stringByAppendingPathComponent:downloadTask.response.suggestedFilename];    //将临时文件复制或剪切到caches文件夹    NSFileManager *fileManager = [NSFileManager defaultManager];    //AtPath : 剪切前的文件路径    //toPath : 剪切后的文件路径    //因为文件都是下载到临时文件夹,下载完成后会删除,所以必须移位置    [fileManager moveItemAtPath:location.path toPath:file error:nil];       // 提示下载完成    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"下载完成" message:downloadTask.response.suggestedFilename delegate:self cancelButtonTitle:nil otherButtonTitles: nil];    [alert show];    [self performSelector:@selector(dismissAlert:) withObject:alert afterDelay:2];        //将下载按钮置灰    self.downBtn.selected = NO;    self.downBtn.enabled = NO;}/** *  每次写入沙盒完毕后调用,在这里可以设置进度条数据等操作 *  totalBytesWritten/totalBytesExpectedToWrite,这两个用来监视下载进度 * *  @param bytesWritten              这次写入的大小 *  @param totalBytesWritten         已经写入沙盒的大小 *  @param totalBytesExpectedToWrite 文件总大小 */-(void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask               didWriteData:(int64_t)bytesWrittentotalBytesWritten:(int64_t)totalBytesWrittentotalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite{    //注意该处的progress,等号右边必须强制转换为double型,进度条才有动画效果,否则只有在下载完成后才有    self.progressView.progress = (float)totalBytesWritten/totalBytesExpectedToWrite;        //设置成百分比形式    NSString *percent = [NSString stringWithFormat:@"下载进度 %0.0f%%", (double)totalBytesWritten/totalBytesExpectedToWrite*100];    self.progressLabel.text = percent;}

其中一些点要注意下:

一、
UIProgressView的progress为float型,所以设置时也要为float型,否则不显示动画效果

self.progressView.progress = (float)totalBytesWritten/totalBytesExpectedToWrite;

效果而下:

没有强制转换

self.progressView.progress = totalBytesWritten/totalBytesExpectedToWrite;

效果而下:

二、

NSSearchPathForDirectoriesInDomains可以用来获取app的私有文件路径,即沙盒中的文件夹列表,获取的为数组形式。

//获取Document文件夹NSString *document = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];//获取Cache文件夹NSString *caches = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];

 

转载于:https://www.cnblogs.com/Apologize/p/4812703.html

你可能感兴趣的文章
VUE-es6
查看>>
MySQL-5.7 高阶语法及流程控制
查看>>
C++学习笔记(十)——向上造型
查看>>
2017/6/16
查看>>
LeetCode 445——两数相加 II
查看>>
预备作业03 20162308马平川
查看>>
【Java】嵌套For循环性能优化案例
查看>>
面试了一个开发人员
查看>>
软件工程及软件项目开发流程
查看>>
关于android4.3 bluetooth4.0的那些事儿
查看>>
嵌入式成长轨迹14 【嵌入式环境及基础】【Linux下的C编程 上】【gcc、gdb和GNU Make】...
查看>>
C语言讲义——变量的输出
查看>>
shell脚本 ----每天学一点shell
查看>>
FZU2150 :Fire Game (双起点BFS)
查看>>
php_常用操作_读取文件_数据库操作
查看>>
Linux中GCC源码编译安装
查看>>
equals与==关于Object覆盖和重载问题
查看>>
KVO
查看>>
js基础教程四之无缝滚动
查看>>
关于C51 keil使用中.c文件的链接心得
查看>>