zoukankan      html  css  js  c++  java
  • IOS断点下载

    下载的一些用法

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

     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)bytesWritten
    totalBytesWritten:(int64_t)totalBytesWritten
    totalBytesExpectedToWrite:(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)bytesWritten
    totalBytesWritten:(int64_t)totalBytesWritten
    totalBytesExpectedToWrite:(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];
  • 相关阅读:
    css-断网图片加载失败,图片表情与文字对齐
    工作中遇到一些不会写的样式
    基础知识题目
    前端基础知识html css
    js match
    jquery.extend()与jquery.fn.extend()的区别
    js apply 与 call
    jdk安装
    js数组操作各种方法
    js获取日期
  • 原文地址:https://www.cnblogs.com/Apologize/p/4812703.html
Copyright © 2011-2022 走看看