SODownloader 使用介绍

scfhao edited this page Aug 11, 2017 · 2 revisions

为方便大家可以用最少的时间在自己的应用中实现下载功能,我决定写一篇啰嗦的文章来介绍如何使用 SODownloader 进行下载。从以下六个方面介绍。

  1. 适配下载模型。
  2. 创建 SODownloader 对象。
  3. 调用下载控制方法。
  4. 观察下载状态。
  5. 下载完成后的处理。
  6. 支持后台下载

适配下载模型

将你要下载的模型对象适配 SODownloadItem 协议(可以参考示例工程中的 SOMusic 类),SODownloadItem 协议中定义了一个下载模型可能需要具备的熟悉,比如下载地址so_downloadURL、下载状态so_downloadState、下载进度so_downloadProgress、下载速度so_downloadSpeed、产生的错误so_downloadError,其中必须实现so_downloadURL方法来返回模型对应的下载地址。

创建 SODownloader 对象

SODownloader 对象可以创建成全局的对象,这样你可以在不同的界面中访问它。如果下载多种类型的文件,建议为每一类创建一个 SODownloader 对象,这样其下载列表中就都是同一个类型的对象了。创建 SODownloader 对象时最后一个 Block 参数为下载完成后的处理,参照下载完成后的处理

- (instancetype)initWithIdentifier:(NSString *)identifier timeoutInterval:(NSTimeInterval)timeoutInterval completeBlock:(SODownloadCompleteBlock_t)completeBlock;

创建 SODownloader 后,可以根据需求对其进行配置:

/// 下载可同时进行的最大下载数
@property (nonatomic, assign) NSInteger maximumActiveDownloads;
/// 设置是否可以使用蜂窝网络进行下载
@property (nonatomic, assign) BOOL allowsCellularAccess;
/// 设置下载请求的请求头
- (void)setValue:(nullable NSString *)value forHTTPHeaderField:(NSString *)field;
/// 设置可接收的文件类型
@property (nonatomic, copy, nullable) NSSet <NSString *> *acceptableContentTypes;

调用下载控制方法

SODownloader 提供了完善的下载控制方法

// 下载:将一个或一组模型加入下载队列
- (void)downloadItem:(id<SODownloadItem>)item;
- (void)downloadItem:(id<SODownloadItem>)item autoStartDownload:(BOOL)autoStartDownload;
- (void)downloadItems:(NSArray<SODownloadItem>*)items;
- (void)downloadItems:(NSArray<SODownloadItem> *)items autoStartDownload:(BOOL)autoStartDownload;
// 暂停:用于等待或下载中状态的项目
- (void)pauseItem:(id<SODownloadItem>)item;
- (void)pauseAll;
// 继续:用于已暂停或失败状态的下载项
- (void)resumeItem:(id<SODownloadItem>)item;
- (void)resumeAll;
// 取消:用于取消下载列表中尚未下载完成的项目
- (void)cancelItem:(id<SODownloadItem>)item;
- (void)cancelItems:(NSArray<SODownloadItem>*)items;
- (void)cancenAll;
/// 将之前下载的对象通过此方法告诉 SODownloader,SODownloader 对象会将其标记为已下载
- (void)markItemsAsComplate:(NSArray<SODownloadItem>*)items;
// 删除:删除已下载的项目
- (void)removeCompletedItem:(id<SODownloadItem>)item;
- (void)removeAllCompletedItems;

观察下载状态

SODownloader 推荐使用 KVO 对下载状态的改变进行观察。

观察某个下载模型的下载状态

通过观察下载模型的so_downloadProgress来获取下载模型对应的下载进度的改变,然后更新UI。

通过观察下载模型的so_downloadState属性来获取下载模型的下载状态改变,SODownloader 对下载模型所处的阶段封装了七个下载状态。

typedef NS_ENUM(NSUInteger, SODownloadState) {
    /* 默认状态,没有加入下载列表 */
    SODownloadStateNormal,
    /* 等待下载 */
    SODownloadStateWait,
    /* 正在下载 */
    SODownloadStateLoading,
    /* 下载暂停 */
    SODownloadStatePaused,
    /* 定制处理,参照[下载完成后的处理]小节 */
    SODownloadStateProcess,
    /* 下载完成 */
    SODownloadStateComplete,
    /* 下载失败,处于此状态时可访问下载模型的`so_downloadError`属性 */
    SODownloadStateError,
};

观察下载队列的状态

SODownloader 内置了两个数组:下载队列(downloadArray)和已下载队列(completeArray),其中下载队列中包含了已加入下载但未下载完成的各个状态的模型。

可以通过观察 SODownloader 对象的SODownloaderDownloadArrayObserveKeyPath来获取下载队列的变化。

可以通过观察 SODownloader 对象的SODownloaderCompleteArrayObserveKeyPath来获取已下载队列的变化。

下载完成后的处理

通常需要对下载完成的文件进行自定义处理,比如对文件进行解压、解析或在数据库中保存已下载数据等,SODownloader 的初始化方法中的completeBlock参数提供了这个处理时机。每完成一个下载任务时,这个 block 会被调用一次对本次完成的模型进行处理,在执行这个处理时,该下载模型会处于SODownloadStateProcess状态。

/**
@param downloader SODownloader 对象
@param item 本次下载完成的模型对象
@param location 该模型对应的下载文件的保存位置,你可以在这里把文件移动到要保存的目的位置
@return 在处理下载完成的文件时,不可避免的会遇到一些问题,比如文件无法解压、解析失败等,如果发生了失败,在这个 block 中返回产生的 NSError 对象即可,SODownloader 会将失败的下载模型的`so_downloadState`置为`SODownloadStateError`并将其`so_downloadError`赋值为返回的 NSError 对象;如果在处理下载完成的文件时没有发生错误,在这个 block 中返回 nil,SODownloader 设定其下载状态为`SODownloadStateComplete`。
*/
typedef NSError *_Nullable(^SODownloadCompleteBlock_t)(SODownloader *downloader, id<SODownloadItem> item, NSURL *location);

支持后台下载

使用 SODownloader 时,想支持后台下载非常简单。下面示例代码中的 musicDownloader 来自示例工程。

  1. 当有后台下载任务完成时,应用被唤醒,下面的 AppDelegate 类的方法会被调用
- (void)application:(UIApplication *)application handleEventsForBackgroundURLSession:(NSString *)identifier completionHandler:(void (^)())completionHandler {
    SODebugLog(@"%@", NSStringFromSelector(_cmd));
#warning 根据identifier找到下载管理器,如果是后台下载事件,交由下载管理器处理
    if ([identifier isEqualToString:[SODownloader musicDownloader].downloaderIdentifier]) {
        [[SODownloader musicDownloader] setDidFinishEventsForBackgroundURLSessionBlock:^(NSURLSession * _Nonnull session) {
            completionHandler();
        }];
    } else {
        // 处理其他的后台会话事件
    }
}
  1. 当 App 被唤醒时,之前创建的 SODownloader 对象已经被释放,所以这里需要重建之前的 SODownloader 对象,包括恢复其下载队列,这样 SODownloader 就可以接着下载队列中的其他任务了。单例模式很好的解决了这里的痛点,即保证了在任何地方都可以轻松的获取下载器对象,又可以在任何需要重建下载器的时候重建一个一摸一样的对象。重建 SODownloader 对象的代码可以在示例工程的SODownloader+MusicDownloader.m文件中的+ (instancetype)musicDownloader;方法实现。

结尾

其实,我特别不喜欢在文章中贴太多代码,这样不仅会导致篇幅太长且令读的人失去继续读下去的兴趣,但不贴代码又觉得可能会解释不清楚,所以我还是贴了部分代码,要看完整的代码,可以克隆示例工程

You can’t perform that action at this time.
You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session.
Press h to open a hovercard with more details.