您好,欢迎来电子发烧友网! ,新用户?[免费注册]

您的位置:电子发烧友网>源码下载>通讯/手机编程>

封装下载管理器实例教学

大小:0.3 MB 人气: 2017-09-26 需要积分:1

  第一节:功能说明

  首先,本篇文章教大家写一个最简单的下载管理器,不包含上传管理器。不过,上传管理器与下载管理器是一样的,后面会抛砖引玉,大家可以各自去尝试!

  本篇文章所讲解的下载管理器具备以下功能:

  开始下载某个视频

  挂起某个视频下载(暂停下载)

  恢复某个视频下载(继续下载)

  可设置下载最大并发量

  添加到下载队列

  以下便是最基本的功能了,那么我们就根据这几个基本功能来实现。至于要做到后台自动下载及退出App,下次进入再自动恢复到上一次退出的状态的,这些不在本demo范围之内!

  为了demo的简单,一切从简!

  第二节:设计理念

  设计理念通常都希望简单使用且易扩展易维护

  与具体的下载类型无关,比如不管是视频下载还是音频下载又或是普通文件下载,都没有关系,都可通用

  单个下载应保持功能的单一性,专心做一件事

  第三节:如何设计整个下载管理器

  考虑到需要记录进度及状态,所以一旦开启下载,整个app过程中都会存在,可考虑使用单例,也可以考虑非单例,但是非单例模式也得保证只创建一遍并交给appDelegate持有,其实与单例设计相当的。为了简化,这里采用的是单例设计。所以,下载管理器以单例形式存在。

  考虑到需要处理并发下载问题,因此使用NSOperationQueue

  考虑到下载类的功能单一性,采用子类化NSOperation

  考虑到使用下载功能与文件类型无关,可定义协议,使model必须遵守,比如豆瓣开源的DOUAudioStreamer就是采用这种方式来实现

  但是,为了demo的简单,这里没有定义协议,直接使用model了。大家可以在真正设计时,采用协议的式,以支持任意model。笔者在项目中真正去写的时候,也会采用协议的方式,支持下载、上传做任意类型的文件,包括视频、音频等。

  本demo中,主要设计以下几个类:

  HYBVideoOperation:子类化的NSOperation,用于专门做下载

  HYBVideoModel:视频下载数据模型,包括视频下载地址、存储地址、进度、状态等,并持有HYBVideoOperation,以方便管理

  HYBVideoManager:下载管理器,管理所有的HYBVideoModel

  然后,我们还需要与UI交互,所以在cell中需要model。HYBVideoCell类为cell,强引用model!

  那么,这整个交互是这样的:

  HYBVideoManager —–》管理所有的HYBVideoModel

  每个HYBVideoModel—–》持有一个HYBVideoOperation

  HYBVideoOperation—-》弱持有一个HYBVideoModel

  HYBVideoCell —–》持有一个HYBVideoModel,当进度或状态变化时,更新UI

  所设计的回调全放在HYBVideoModel中,当HYBVideoModel的进度属性值和状态值发生变化时反馈到UI变化上!

  第四节:子类化NSOperation

  关于子类化NSOperation需要做哪些事件,最好还是先阅读笔者之前所写的一篇文章NSOperation/Queue,不过下面我也会列出一些要点:

  重写start方法时,要做好isCannelled的判断

  重写isExecuting、isFinished、isConcurrent

  重写cancel,并处理好isCancelled KVO处理

  我们设计Operation时,采用NSURLSession实现下载,通过控制NSURLSessionDownloadTask,可实现下载、暂停下载和断点下载功能。

  我们整个头文件的设计为:

  @class HYBVideoModel;

  @interface NSURLSessionTask (VideoModel)

  // 为了更方便去获取,而不需要遍历,采用扩展的方式,可直接提取,提高效率

  @property (nonatomic, weak) HYBVideoModel *hyb_videoModel;

  @end

  @interface HYBVideoOperation : NSOperation

  - (instancetype)initWithModel:(HYBVideoModel *)model session:(NSURLSession *)session;

  @property (nonatomic, weak) HYBVideoModel *model;

  // 可以不公开此属性

  @property (nonatomic, strong, readonly) NSURLSessionDownloadTask *downloadTask;

  - (void)suspend;

  - (void)resume;

  - (void)downloadFinished;

  @end

  这里还扩展了NSURLSessionTask,将模型与之关联,注意采用弱引用哦!我不知道这样设计是否合理,但是我个人认为这么设计的好处是:接口简单,与外部没有直接的联系,session来源于下载管理类,这样可统一管理。

  当下载完成之后,一定要回调downloadFinished,目的是让任务退队。要让任务退队,只有保证isFinished为YES才能退队!

  [self willChangeValueForKey:@“isFinished”];

  [self willChangeValueForKey:@“isExecuting”];

  _executing = NO;

  _finished = YES;

  [self didChangeValueForKey:@“isExecuting”];

  [self didChangeValueForKey:@“isFinished”];

  因为任务完成还可以重新下载,通常情况下不会自动退队。

  第五节:反馈到UI展示进度及状态提示

  我们通过模型来反馈到UI上,在进度和状态变化时,可以回调来更新UI。

  首先,下载过程有很多种状态,我们定义成枚举:

  typedef NS_ENUM(NSInteger, HYBVideoStatus) {

  kHYBVideoStatusNone = 0, // 初始状态

  kHYBVideoStatusRunning = 1, // 下载中

  kHYBVideoStatusSuspended = 2, // 下载暂停

  kHYBVideoStatusCompleted = 3, // 下载完成

  kHYBVideoStatusFailed = 4, // 下载失败

  kHYBVideoStatusWaiting = 5 // 等待下载

  };

  设计属性:

  typedef void(^HYBVideoStatusChanged)(HYBVideoModel *model);

  typedef void(^HYBVideoProgressChanged)(HYBVideoModel *model);

  @interface HYBVideoModel : NSObject

  @property (nonatomic, copy) NSString *videoId;

  @property (nonatomic, copy) NSString *videoUrl;

  @property (nonatomic, copy) NSString *imageUrl;

  @property (nonatomic, copy) NSString *title;

  // 用于断点下载记录,其实应该要存储到文件中,然后记录路径,但是为了简单,demo就不这么做了

  @property (nonatomic, strong) NSData *resumeData;

  // 下载后存储到此处

  @property (nonatomic, copy) NSString *localPath;

  @property (nonatomic, copy) NSString *progressText;

  // 非常关键的属性,进度变化会自动回调onProgressChanged

  @property (nonatomic, assign) CGFloat progress;

  // 状态变化会自动回调onStatusChanged

  @property (nonatomic, assign) HYBVideoStatus status;

  // 这里为什么要引用operation且是强引用?因为管理器直接管理的是model,

  // 而真正做下载任务的是operation。

  // 为什么没有将这两个分别作为属性呢?为了整体更简单!

  @property (nonatomic, strong) HYBVideoOperation *operation;

  @property (nonatomic, copy) HYBVideoStatusChanged onStatusChanged;

  @property (nonatomic, copy) HYBVideoProgressChanged onProgressChanged;

  @property (nonatomic, readonly, copy) NSString *statusText;

  @end

  当然,不同的人来设计,可能会有不同的方式。我分析过好几种设计方式,但是列出来的好处,不如这一种。

  当进度或者状态变化时,自动地回调:

  - (void)setProgress:(CGFloat)progress {

  if (_progress != progress) {

  _progress = progress;

  if (self.onProgressChanged) {

  self.onProgressChanged(self);

  } else {

  NSLog(@“progress changed block is empty”);

  }

  }

  }

  - (void)setStatus:(HYBVideoStatus)status {

  if (_status != status) {

  _status = status;

  if (self.onStatusChanged) {

  self.onStatusChanged(self);

  }

  }

  }

  这样回调与下载管理类及下载类都没有直接的关系了,而model的回调直接反馈到UI层了!

非常好我支持^.^

(0) 0%

不好我反对

(0) 0%

      发表评论

      用户评论
      评价:好评中评差评

      发表评论,获取积分! 请遵守相关规定!