iOS 下载管理器(下)

简介: iOS 下载管理器(下)

二、NSURLSession 下载大文件,以下测试我们使用Apache 服务器里面的数据



image.png


  • 2.1、NSURLSession 简介 以及 简单使用,完整代码在JKNSURLSession中的 Test1ViewControllerNSURLSession是在iOS 7.0(15年)的时候推出的,在最开始的时候也会出现峰值,后来解决后大家才重新使用NSURLSession,NSURLSession所有的任务都是session发起的,默认所有任务都是“挂起”的,需要resume执行。
  • 简单的使用:


-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
     // 1.创建url: http://localhost/test.json
     NSURL *url = [NSURL URLWithString:@"http://localhost/test.json"];
     [self taskWithUrl:url];
}
-(void)taskWithUrl:(NSURL *)url{
     [[[NSURLSession sharedSession]dataTaskWithURL:url completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
        // 反序列化
        id result = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
         NSLog(@"%@",result);
     }] resume];
}


提示:NSURLSession 是一个单利,目的是使开发更容易,默认是不启动的,需要开发者调用  resume 启动 NSURLSession,如上面


  • 2.2、NSURLSession 简单的下载,完整代码在JKNSURLSession中的 Test2ViewController


-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
     // 1.创建url:http://localhost
     NSURL *url = [NSURL URLWithString:@"http://localhost/2ittt-zm.mp4"];
     [self taskWithUrl:url];
}
-(void)taskWithUrl:(NSURL *)url{
    /*
      如果在回调方法中,不做任何处理,下载的文件会被删除
      下载是默认下载到tmp文件夹,系统会自动回收这个区域
      设计目的:
      1.通常从网络下载文件,什么样的格式文件最多?zip
      2.如果是zip包,下载之后要解压
      3.解压之后,原始的zip就不需要了。系统会自动帮你删除
     */
     [[[NSURLSession sharedSession]downloadTaskWithURL:url completionHandler:^(NSURL * _Nullable location, NSURLResponse * _Nullable response, NSError * _Nullable error) {
           NSLog(@"%@",location);
     }]resume];
}


提示:location打印是:file:///Users/wangchong/Library/Developer/CoreSimulator/Devices/643379A0-0449-4FE2-AD19-71258BDDBAE6/data/Containers/Data/Application/E6F1AABA-BDBE-4191-A167-02D5DCD19D41/tmp/CFNetworkDownload_OaisFm.tmp,我们可以看到 tmp,临时存放下载文件的地方


  • 2.3、文件解压缩,完整代码在JKNSURLSession中的 Test3ViewController
  • (1)、这里我们需要使用一个工具SSZipArchive,在demo里面有



image.png


image.png

  • SSZipArchive的功能压缩文件解压文件
  • (2)、解压我们服务器的一个文件到 Library/Caches里面


-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
    // 1.创建url:http://localhost
    NSURL *url = [NSURL URLWithString:@"http://localhost/ftp.docx.zip"];
    [self taskWithUrl:url];
}
-(void)taskWithUrl:(NSURL *)url{
    [[[NSURLSession sharedSession]downloadTaskWithURL:url completionHandler:^(NSURL * _Nullable location, NSURLResponse * _Nullable response, NSError * _Nullable error) {
         NSLog(@"%@",location);
         // 文件解压目标路径,不能指定目标文件。因为我们解压文件会产生多个文件
         NSString *cachePath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES)lastObject];
         [SSZipArchive unzipFileAtPath:location.path toDestination:cachePath];
    }]resume];
}


image.png


  • 2.4、NSURLSession下载进度监听,完整代码在JKNSURLSession中的 Test4ViewController
  • (1)、创建一个 NSURLSession对象


// 全局的网络会话,管理所有的网络任务
@property(nonatomic,strong) NSURLSession *session;
-(NSURLSession *)session{
     if (!_session) {
          /**
           全局网络环境的一个配置
           比如:身份验证,浏览器类型以及缓存,超时,这些都会被记录在
          */
          NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];
          _session = [NSURLSession sessionWithConfiguration:config delegate:self delegateQueue:nil];
      }
     return _session;
}
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
       // 1.创建url:http://localhost
       NSURL *url = [NSURL URLWithString:@"http://localhost/2ittt-zm.mp4"];
       //如果你要监听下载进度,必须使用代理。
       //如果你要更进下载进度,就不能block 。
       [[self.session downloadTaskWithURL:url]resume];
}


提示:

  • 如果你要监听下载进度,必须使用代理。
  • [NSURLSession sharedSession] 是全局的单例。整个系统都会用,也就是其他的应用程序也会用
  • 如果你要更进下载进度,就不能block 。


  • (2)、常用的代理方法(其中下载完成的方法是在iOS7.0之后必须要写的,在iOS7之前,下面的三个方法都必须写)


/**
   1、下载完成的方法
 */
-(void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location{
     NSLog(@"下载完成");
}
/**
  2、下载续传数据的方法
*/
-(void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didResumeAtOffset:(int64_t)fileOffset expectedTotalBytes:(int64_t)expectedTotalBytes{
 }
/**
  3、下载进度的方法
  @param session 网络会话
  @param downloadTask 调用代理方式的下载任务
  @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{
     float progress = (float)totalBytesWritten/totalBytesExpectedToWrite;
     NSLog(@"进度=%f",progress);
}


  • 2.5、自定义progressview,完整代码在JKNSURLSession中的 Test5ViewController
  • (1)、自定义progressview我们选择继承于 UIButton,原因是:button可以设置文字,展示的时候比较方便,当然也可以使用其他的控件,比如lable,那么我们自定义一个类 JKProgressBtn 继承于UIButton,代码如下
  • JKProgressBtn.h里面的代码


#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@interface JKProgressBtn : UIButton
/**
   表示进度的值
*/
@property(nonatomic,assign) float progress;
@end
NS_ASSUME_NONNULL_END
  • JKProgressBtn.m里面的代码


#import "JKProgressBtn.h"
@implementation JKProgressBtn
-(instancetype)initWithFrame:(CGRect)frame{
      self = [super initWithFrame:frame];
      if (self) {
         [self setTitleColor:[UIColor brownColor] forState:UIControlStateNormal];
      }
      return self;
}
-(void)setProgress:(float)progress{
      _progress = progress;
      // 进度的Label
      [self setTitle:[NSString stringWithFormat:@"%0.2f%%",_progress*100] forState:UIControlStateNormal];
      // 刷新视图
      [self setNeedsDisplay];
}
-(void)drawRect:(CGRect)rect{
      CGSize s = rect.size;
      // 圆心
      CGPoint center = CGPointMake(s.width*0.5, s.height*0.5);
      // 半径
      CGFloat r = (s.height > s.width) ? s.width*0.5:s.height*0.5;
      r = r - 5;
      // 其实角度
      CGFloat startAngle = -M_PI_2;
      // 结束角度
      CGFloat endAngle = self.progress*2*M_PI + startAngle;
      /**
         第1个参数:圆心
         第2个参数:半径
         第3个参数:起始角度
         第4个参数:结束角度
         第5个参数:YES:顺时针 / NO:逆时针
       */
      UIBezierPath *bezierPath = [UIBezierPath bezierPathWithArcCenter:center radius:r startAngle:startAngle endAngle:endAngle clockwise:YES];
      // 圆环的宽度
      bezierPath.lineWidth = 10.0;
      // 设置圆环的样式(圆形)
      bezierPath.lineCapStyle = kCGLineCapRound;
      // 给圆环添加颜色
      [[UIColor purpleColor]setStroke];
      // 绘制路径
      [bezierPath stroke];
}
@end


提示:UIBezierPath:贝塞尔曲线的起始角度是时钟的3点,也就是数学上x的正轴方向,故上面我们把起始角度设置为-M_PI_2,也就是 时钟的12点,同理数学上y的正轴方向,其他的参数在上面描述的很清楚

  • 解释一下: bezierPath.lineWidth = 10.0;,在贝塞尔曲线里面,半径决定后,圆环的宽度是以半径向外扩展的,所以才有上面的: r = r - 5;


  • (2)、JKProgressBtn 的使用,在NSURLSession下载进度的方法里面刷新JKProgressBtn的进度,如下:


image.png

  • 先在控制器里面定义一个 JKProgressBtn属性并初始化添加到控制器


// 进度的View
@property(nonatomic,strong) JKProgressBtn *progressView;
-(JKProgressBtn *)progressView{
     if (!_progressView) {
          _progressView = [[JKProgressBtn alloc]initWithFrame:CGRectMake([UIScreen mainScreen].bounds.size.width/2-50, [UIScreen mainScreen].bounds.size.height/2-50, 100, 100)];
          _progressView.backgroundColor = [UIColor yellowColor];
     }
     return _progressView;
}
// 添加进度View
[self.view addSubview:self.progressView];
  • 在下载进度的方法里面设置主线程刷新 progressView的值


/**
  3、下载进度的方法
  @param session 网络会话
  @param downloadTask 调用代理方式的下载任务
  @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{
       float progress = (float)totalBytesWritten/totalBytesExpectedToWrite;
       NSLog(@"进度=%f",progress);
       dispatch_async(dispatch_get_main_queue(), ^{
               self.progressView.progress = progress;
       });
}

提示:NSURLSession创建的下载是在子线程执行的,所以上面才在主线程刷新UI


  • 2.6、断点续传,完整代码在JKNSURLSession中的 Test6ViewController
  • (1)、创建三个按钮,开始下载暂停下载继续下载


image.png


image.png


  • (2)、创建一个全局的下载任务


/**
   设置一个全局的下载任务
 */
@property(nonatomic,strong) NSURLSessionDownloadTask *downloadTask;
  • (3)、开始下载、暂停下载,继续下载 三个方法对应的代码如下


#pragma mark 开始下载
-(void)startLoadTask{
       NSLog(@"开始下载");
       // 1.创建url:http://localhost
       NSURL *url = [NSURL URLWithString:@"http://localhost/2ittt-zm.mp4"];
       self.downloadTask = [self.session downloadTaskWithURL:url];
       // 2、执行下载
       [self.downloadTask resume];
}
#pragma mark 暂停下载
-(void)pauseLoadTask{
       NSLog(@"暂停下载");
       [self.downloadTask cancelByProducingResumeData:^(NSData * _Nullable resumeData) {
           self.resumeData = resumeData;
           //释放任务
           self.downloadTask = nil;
       }];
}
#pragma mark 继续下载
-(void)resumeLoadTask{
       NSLog(@"继续下载");
      // 防止继续下载被执行两次,故下面把self.resumeData赋为nil
      if (self.resumeData == nil) return;
      self.downloadTask = [self.session downloadTaskWithResumeData:self.resumeData];
      self.resumeData = nil;
      [self.downloadTask resume];
}


提示:断点续传其实也就是在暂停下载的时候获取下载的resumeData,再次接着下载的时候,用resumeData再获取一个NSURLSessionDownloadTask,从而接着下载


  • 2.7、NSURLSession 强引用 问题
  • (1)、NSURLSession是一个强引用,在下载完成的时候要进行释放,不管是是否支持不在当前界面下载,当所有的下载任务都完成后,需要进行释放 session,并赋nil,否则会造成内存泄漏


/**
   1、下载完成的方法
 */
-(void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location{
    NSLog(@"下载完成");
    [self.session finishTasksAndInvalidate];
    self.session = nil;
}
  • (2)、如果只支持当前界面下载的情况,退出当前界面,取消下载,session 赋nil


[self.session invalidateAndCancel];
self.session = nil;


三、下载管理器  demo地址:JKDownloaderKit



  • 3.1、下载思路
  • (1)、创建另两个文件夹:JKDownloadCompleted(下载完成的文件夹)和JKDownLoading(下载中的文件夹),在下载中的资源会存在JKDownLoading中,下载完成后会移动到JKDownloadCompleted里面


image.png


  • (2)、先查看服务器上的文件大小
  • (3)、查看本地是否存在文件,如果存在如下
  • 如果文件小于服务器文件的大小,从本地文件长度开始下载(断点续传)
  • 如果文件等于服务器文件的大小,再把文件生成一个MD5与服务器对文件返回的MD5做对比,如果一样,代表下载完成
  • 如果文件大于服务器文件的大小,发生错误,直接删除文件,重新下载
  • (4)、如果本地不存在该文件,直接下载


  • 上传视频的思路:
    在上传视频的时候,如果视频断开了(程序退出了),那么就要去服务器请求看看自己之前上传了多少,接着上传就好,和视频的下载原理是一样的,对比
  • 总体思路图


image.png


  • (5)、在监听下载的方法中,当下载完成后做如下的操作
  • 在没有 error 的情况下,文件下载是完毕了,但是不一定成功,分析如下
  • 判断, 本地缓存==文件总大小 (如果不相等,说明下载有问题,删除下载路径下的文件,重新下载;如果相等在验证文件内容的MD5值是否一样,一样的话才是真正的下载完成,否则下载是有问题的,删除下载路径下的文件,重新下载)
  • 下载-文件完整性验证机制:验证文件的合法性, 下载数据是否完整可用
  • 服务器返回文件下载信息的同时, 会返回该文件内容的md5值
  • 本地下载完成后, 可以, 在本地已下载的文件的MD5值和服务器返回的进行对比;
  • 为了简单, 有的, 服务器返回的下载文件MD5值, 直接就是命名称为对应的文件名称


  • 3.2、创建一个管理下载的类
  • 命名下载的类为:JKDownLoader,继承于 NSObject,定义一个下载的方法


/**
  定义一个下载的方法
  (1)、先查看服务器上的文件大小
  (2)、查看本地是否存在文件,如果存在如下
         2.1、如果文件小于服务器文件的大小,从本地文件长度开始下载(断点续传)
         2.2、如果文件等于服务器文件的大小,再把文件生成一个MD5与服务器对文件返回的MD5做对比,如果一样,代表下载完成
         2.3、如果文件大于服务器文件的大小,发生错误,直接删除文件,重新下载
  (3)、如果本地不存在该文件,直接下载
  @param url 下载的url
*/
-(void)downloadWithUrl:(NSURL *)url{
}
  • 3.3、从 服务器 获取下载文件的信息
  • 我们需要设置下载的总大小以及下载后存放的位置


/**
   文件的总大小
 */
@property(nonatomic,assign) long long expectdContentLength;
/**
  文件的下载路径
 */
@property(nonatomic,strong) NSString *downloadPath;
  • 获取文件信息的私有ipa


#pragma mark 私有方法
-(void)selectServerFileInfoWithUrl:(NSURL *)url{
    // 1.请求信息:我们只需要获取头部信息就好
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url cachePolicy:1 timeoutInterval:kTimeOut];
    request.HTTPMethod = @"HEAD";
    // 2.建立网络连接
    NSURLResponse *response = nil;
    [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:NULL];
    NSLog(@"%@ %@ %lld",data,response,response.expectedContentLength);
    // 3.记录服务器的文件信息
    // 3.1、文件长度
    self.expectdContentLength = response.expectedContentLength;
    // 3.2、建议保存的文件名字,将在文件保存在tmp,系统会自动回收
    self.downloadPath = [NSTemporaryDirectory() stringByAppendingPathComponent:response.suggestedFilename];
}


  • 提示:这里采用的是同步方法,因为我们需要根据文件的信息去操作下面的下载操作,不能使用异步
  • NSURLConnection:默认是在 主线程 进行操作,而NSURLSession 是在 子线程 进行操作


  • 3.4、检查 本地 下载文件的信息


/**
   2.从本地检查要下载的文件信息(除了文件下载完,其他的情况都需要下载文件)
   @return YES:需要下载,NO:不需要下载
 */
-(BOOL)checkLocalFileInfo{
      long long fileSize = 0;
      // 1.判断文件是否存在
      if ([[NSFileManager defaultManager]fileExistsAtPath:self.downloadPath]) {
           // 获取本地存在文件大小
           NSDictionary *attributes = [[NSFileManager defaultManager]attributesOfItemAtPath:self.downloadPath error:NULL];
           NSLog(@"%@",attributes);
           fileSize = [attributes[NSFileSize] longLongValue];
       }
       // 2.根据文件大小来判断文件是否存在
       if(fileSize > self.expectdContentLength){
            // 文件异常,删除该文件
            [[NSFileManager defaultManager]removeItemAtPath:self.downloadPath error:NULL];
            fileSize = 0;
       }else if (fileSize == self.expectdContentLength) {
            // 文件已经下载完
            return NO;
       }
       return YES;
}
  • 3.5、文件下载实现
  • (1)、定义一个属性保存下载的地址 URL


/**
   视频的下载地址 URL
 */
@property(nonatomic,strong) NSURL *downloadUrl;
  • (2)、视频下载从当前的字节开始下载,不管字节是不是0,都是检查过本地路径的字节,本地有的话,当前字节就不是0,也就是断点续传;没有的话就是0,也就是从头开始下载
  • 拓展一个 HTTP 属性 Range,下载会用到


Bytes = 0-499  : 从 0 到 499 的 500 个字节
Bytes = 500-999 : 从500-999的第二个500字节
Bytes = 500-  : 从500开始到以后所有的字节
Bytes = -500 最后500个字节
Bytes = 500-699,800-1299,1600-2000 同时指定多个范围
  • (3)、开始下载,这里先使用上面 中的 NSURLConncetion放在子线程,开启Runloop的代理方法来下载,把 NSURLConncetion 放在异步并发的队列,用文件流拼接写入路径,下面只展示部分代码,完整代码看 demo


/* 保存文件的输出流
   - (void)open; 写入之前,打开流
   - (void)close; 写入完毕之后,关闭流
 */
@property(nonatomic,strong)NSOutputStream *fileStream;
/*
   保存下载线程的运行循环,也就是下载任务的 runloop
 */
@property(nonatomic,assign)CFRunLoopRef downloadRunloop;
#pragma mark 下载文件
-(void)downloadFile{
     dispatch_async(dispatch_get_global_queue(0, 0), ^{
          // 1.建立请求
          NSMutableURLRequest *request = [[NSMutableURLRequest alloc]initWithURL:self.downloadUrl cachePolicy:1 timeoutInterval:MAXFLOAT];
          // 2.设置下载的字节范围,self.currentLength到之后所有的字节
          NSString *downloadRangeStr = [NSString stringWithFormat:@"bytes=%lld-",self.currentContentLength];
          // 3.设置请求头字段
          [request setValue:downloadRangeStr forHTTPHeaderField:@"Range"];
          // 4.开始网络连接
          NSURLConnection *connection = [NSURLConnection connectionWithRequest:request delegate:self];
          // 5.设置代理工作的操作 [[NSOperationQueue alloc]init] 默认创建一个异步并发队列
          [connection setDelegateQueue:[[NSOperationQueue alloc]init]];
          // 启动连接
          [connection start];
          //5.启动运行循环
          /*
            CoreFoundation 框架 CFRunLoop
            CFRunloopStop() 停止指定的runloop
            CFRunloopGetCurrent() 获取当前的Runloop
            CFRunloopRun() 直接启动当前的运行循环
          */
          // (1)、拿到当前的运行循环
          self.downloadRunloop = CFRunLoopGetCurrent();
          // (2)、启动当前的运行循环
         CFRunLoopRun();
    });
}
#pragma mark NSURLConnection的代理NSURLConnectionDataDelegate的方法
// 1、接收服务器的响应 --- 状态和响应头做一些准备工作
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response{
     self.fileStream = [[NSOutputStream alloc]initToFileAtPath:self.downloadPath append:YES];
     [self.fileStream open];   
}
// 2、接收服务器的数据,由于数据是分块发送的,这个代理方法会被执行多次,因此我们也会拿到多个data
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data{
     // 接收数据,用输出流拼接,计算下载进度
    // 将数据拼接起来,并判断是否可写如,一般情况下可写入,除非磁盘空间不足
    if ([self.fileStream hasSpaceAvailable]) {
         [self.fileStream write:data.bytes maxLength:data.length];
    }
    // 当前长度拼接
    self.currentContentLength += data.length;
    // 计算百分比
    // progress = (float)long long / long long
    float progress = (float)self.currentContentLength/self.expectdContentLength;
    // 传送百分比
    if (self.progress) {
          self.progress(progress);
    }
    NSLog(@"%f %@",progress,[NSThread currentThread]);
}
// 3、接收到所有的数据下载完毕后会有一个通知
- (void)connectionDidFinishLoading:(NSURLConnection *)connection;
{
      NSLog(@"下载完毕");
      [self.fileStream close];
      // 下载完成的回调
      if (self.completion) {
          self.completion(self.downloadPath);
      }
     // 关闭当前下载完的 RunLoop
     CFRunLoopStop(self.downloadRunloop);
}
// 4、下载错误的处理
-(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error{
     NSLog(@"连接失败:%@",error.localizedDescription);
     // 关闭流
     [self.fileStream close];
     // 关闭当前的 RunLoop
     CFRunLoopStop(self.downloadRunloop);
}
  • 3.6、暂停下载操作
    暂停下载操作直接调用:NSURLConnection  的 cancel 就好
  • 3.7、多文件下载管理我们创建一个下载管理器JKDownloaderManger,设置成单利,用来下载多个文件,同时创建下载缓存池,避免多次下载同一个文件
  • (1)、单利的实现(一个静态变量,三个方法,才是完整的单利)


static id instance;
+(instancetype)allocWithZone:(struct _NSZone *)zone{
      static dispatch_once_t onceToken;
      dispatch_once(&onceToken, ^{
            instance = [super allocWithZone:zone];
      });
      return instance;
}
-(id)copy{
      return instance;
}
+(instancetype)shareDownloaderManger{
      static dispatch_once_t onceToken;
      dispatch_once(&onceToken, ^{
            instance = [[self alloc]init];
      });
      return instance;
}
  • (2)、创建字典缓存池


@property(nonatomic,strong) NSMutableDictionary *downloadCache;
  • (3)、下载方法的实现( 以NSURL的url.path 为键 )


-(void)jk_downloadWithUrl:(NSURL *)url withDownProgress:(downProgress)progress completion:(downCompletion)completion fail:(downFailed)failed
{
   // 1.判断缓存池里面是否有同一个下载任务
   JKDownLoader *downLoader = self.downloadCache[url.path];
   if (downLoader != nil) {
        NSLog(@"已经在下载列表中,请不要重复下载");
        return;
   }
   // 2.创建新的下载任务
   downLoader = [[JKDownLoader alloc]init];
   // 3.将下载任务添加到缓存池
   [self.downloadCache setValue:downLoader forKey:url.path];
    __weak typeof(self) weakSelf = self;
    [downLoader jk_downloadWithUrl:url withDownProgress:progress completion:^(NSString * _Nonnull downFilePath) {
           // 1.将下载从缓存池移除
           [weakSelf.downloadCache removeObjectForKey:url.path];
           // 2.执行调用方法的回调
           if (completion) {
                 completion(downFilePath);
           }
    } fail:failed];
}
  • (4)、下载暂停:暂停下载,从缓存池移除该url的path


#pragma mark 暂停某个文件下载
-(void)pauseloadWithUrl:(NSURL *)url{
    // 1.通过url获取下载任务
    JKDownLoader *downLoader = self.downloadCache[url.path];
    // 2.暂停下载
    if (downLoader == nil){
          if (self.failed) {
               self.failed(@"已经暂停下载,请不要重复点击");
          }
          return;
   }
   [downLoader pause];
   // 3.从缓存池移除
   [self.downloadCache removeObjectForKey:url.path];
}


iOS 下载器完整的代码请查看demo


到此下载完毕,下一篇会阐述 下载中下载完成 文件夹里面文件的读取,敬请关注

目录
相关文章
|
Swift iOS开发 开发者
iOS - 跳转App Store下载 app 的两种方式
iOS - 跳转App Store下载 app 的两种方式
2223 0
iOS - 跳转App Store下载 app 的两种方式
|
存储 缓存 iOS开发
iOS 轻量化动态图像下载缓存框架实现
日常开发过程中,图片的下载会占用大量的带宽,图片的加载会消耗大量的性能和内存,正确的使用图片显得尤为重要。 同样也经常需要在各类型控件上读取网络图片和处理本地图片,例如:UIImageView、UIBtton、NSImageView、NSButton等等。
iOS 轻量化动态图像下载缓存框架实现
|
iOS开发
iOS下载文件保存到手机文件指定目录
iOS下载文件保存到手机文件指定目录
1094 0
|
Web App开发 弹性计算 Android开发
阿里云无影云桌面客户端下载Win/Mac/iOS/安卓/Web端均支持
阿里云无影客户端下载系统Win/Mac/iOS/安卓/Web端均支持
4636 0
阿里云无影云桌面客户端下载Win/Mac/iOS/安卓/Web端均支持
|
Linux iOS开发 开发者
WIN11自定义版本ios镜像下载教程
WIN11自定义版本ios镜像下载教程
WIN11自定义版本ios镜像下载教程
|
安全 数据安全/隐私保护 iOS开发
iMazing官网下载安装教程 2023最新版兼容Win和Mac的iOS设备管理软件
iMazing是一款功能强大的iOS设备管理软件,它可以帮助用户备份和管理他们的iPhone、iPad或iPod Touch上的数据。除此之外,它还可以将备份数据转移到新的设备中、管理应用程序、导入和导出媒体文件等。本文将详细介绍iMazing的功能和安全性,并教大家如何使用iMazing来恢复备份数据。
510 0
|
Web App开发 弹性计算 Android开发
阿里云无影客户端下载Windows/Mac/iOS/安卓/Web端操作系统均支持
阿里云无影云桌面客户端下载,无影客户端支持操作系统包括Windows、Mac、Web网页端、iOS客户端和安卓客户端
阿里云无影客户端下载Windows/Mac/iOS/安卓/Web端操作系统均支持
|
iOS开发 芯片 MacOS
macOS Big Sur 正式发布并已开放下载,支持原生运行 iOS 和 iPadOS App
macOS Big Sur 正式发布并已开放下载,支持原生运行 iOS 和 iPadOS App
218 0
|
移动开发 安全 JavaScript
关于ios低版本在app store下载软件时由于版本低导致不能下载的解决办法
关于ios低版本在app store下载软件时由于版本低导致不能下载的解决办法
590 0
关于ios低版本在app store下载软件时由于版本低导致不能下载的解决办法
|
移动开发 Java Linux
iOS上架app store下载步骤
iOS上架app store下载步骤
iOS上架app store下载步骤