MCDownloader(iOS下載器)說明書

示例

前言

不少iOS應用中都須要下載數據,並對這些下載的過程和結果進行管理,所以我纔有了寫這個MCDownloader的想法。在IOS 文件下載器-MCDownloadManager這篇文章中,我使用GCD和集合來實現了這個功能,基本上也能知足需求,這一部分的實現原理主要參考AFNetworking的源碼,有興趣的同窗能夠看看我寫的AFNetworking 3.0 源碼解讀系列html

可是本篇文章中講的MCDownloader的實現原理和上邊提到的不同,是基於NSOperation來實現的,能夠說是我對SDWebImage源碼解讀的一些額外的擴展,一樣,有興趣的同窗能夠看看我寫的SDWebImage源碼解讀系列git

MCDownloader目前的版本是1.0.0,能夠在這裏下載https://github.com/agelessman/MCDownloadergithub

功能

MCDownloader1.0.0版本提供瞭如下幾個功能:緩存

  1. 多線程異步下載,支持自定義併發線程數。在上圖的示例圖中,採用的併發數爲3
  2. 邊下載變保存,這一條是該下載器最重要的思想,數據被實時的保存在本地,同時支持斷點下載
  3. 十分方便的數據獲取能力,經過MCDownloadReceipt來對下載的數據進行抽象,幾乎全部的信息都能在MCDownloadReceipt中獲取
  4. 提供了下載進度,能夠經過接口函數的block監聽下載進度和完成回調,也能夠經過給MCDownloadReceipt綁定block來監聽block回調
  5. 支持顯示當前的下載速度
  6. 支持批量下載,批量取消功能
  7. 支持任務的暫停,取消,刪除功能
  8. 支持下載順序定製,先入先出或者後入先出
  9. 支持後臺和鎖屏下載

如何使用?

開啓下載

每個下載任務的惟一標識是url,所以咱們使用下邊的代碼開始一個下載任務:網絡

[[MCDownloader sharedDownloader] downloadDataWithURL:[NSURL URLWithString:url] progress:^(NSInteger receivedSize, NSInteger expectedSize, NSInteger speed, NSURL * _Nullable targetURL) {
                
  } completed:^(MCDownloadReceipt * _Nullable receipt, NSError * _Nullable error, BOOL finished) {
      NSLog(@"==%@", error.description);
  }];

能夠在上邊的progress和completed中自定義處理方法。進度和完成的block回調都在主線程觸發。多線程

暫停或取消

MCDownloader的暫停和取消功能是同樣的,因爲內部下載是基於NSOperation實現的,所以每個任務就是一個NSOperation,而後再把他們添加到隊列之中。當取消或者暫停一個任務後,在從新恢復下載,實際上會從新把該任務添加到隊列中,這一點必定要注意。併發

使用下邊的代碼來暫停或取消一個下載任務:框架

[[MCDownloader sharedDownloader] cancel:receipt completed:^{
            [self.button setTitle:@"Start" forState:UIControlStateNormal];
        }];

因爲取消不是發生在主線程,因此須要一個completed來捕獲取消成功事件,而後在主線程調用。less

移除數據

經過下邊的方法來移除保存在本地的數據:異步

[[MCDownloader sharedDownloader] remove:receipt completed:^{
            [self.tableView reloadData];
        }];

獲取數據信息

能夠經過下邊的代碼來獲取數據的一些信息,這些信息既能夠在下載過程當中獲取,也能夠在下載完成後獲取。

MCDownloadReceipt *receipt = [[MCDownloader sharedDownloader] downloadReceiptForURLString:self.url];

經過上邊的代碼能夠看出來,url被當作數據的惟一標識。在上圖的例子中,咱們是在cell中更新下載進度的,爲了防止cell的複用問題,我爲每一個receipt綁定了progress和complete回調block:

__weak typeof(receipt) weakReceipt = receipt;
    receipt.downloaderProgressBlock = ^(NSInteger receivedSize, NSInteger expectedSize, NSInteger speed, NSURL * _Nullable targetURL) {
        __strong typeof(weakReceipt) strongReceipt = weakReceipt;
        if ([targetURL.absoluteString isEqualToString:self.url]) {
            [self.button setTitle:@"Stop" forState:UIControlStateNormal];
            self.bytesLable.text = [NSString stringWithFormat:@"%0.1fm/%0.1fm", receivedSize/1024.0/1024,expectedSize/1024.0/1024];
            self.progressView.progress = (receivedSize/1024.0/1024) / (expectedSize/1024.0/1024);
            self.speedLable.text = [NSString stringWithFormat:@"%@/s", strongReceipt.speed ?: @"0"];
        }
        
    };
    
    receipt.downloaderCompletedBlock = ^(MCDownloadReceipt *receipt, NSError * _Nullable error, BOOL finished) {
        if (error) {
            [self.button setTitle:@"Start" forState:UIControlStateNormal];
            self.nameLabel.text = @"Download Failure";
        }else {
            [self.button setTitle:@"Play" forState:UIControlStateNormal];
            self.nameLabel.text = @"Download Finished";
        }
        
    };

取消所有下載和刪除所有數據

在某種場景下須要取消所有的下載,好比說監聽到網絡狀態變成4G時,須要詢問用戶是否繼續下載。又或者在須要清空緩存的時候:

[[MCDownloader sharedDownloader] cancelAllDownloads];

[[MCDownloader sharedDownloader] removeAndClearAll];

上邊說的這些功能,在demo中都有演示。

核心思想

因爲下載功能不算是特別複雜的功能,因此我就簡單的說說內部的實現原理。

在代碼設計之初,我最早寫的類就是MCDownloadReceipt。經過它來對數據進行抽象封裝,咱們先無論它是如何獲取的,只關心它須要暴露多少信息。這個類很簡單,我就不把代碼弄上來了,可是須要注意下邊幾點:

  • 這些屬性被設計成只讀屬性,代表只在該類中獲取數據,不要修改其中的數據
  • receipt須要保存在本地,我採用的是歸檔的方法進行持久化
  • 文件名要作MD5處理
  • 每個receipt都綁定了一個狀態屬性

完成了模型的搭建後,就要處理最基本的下載任務了,MCDownloadOperation繼承自NSOperation,所以在MCDownloadOperation中咱們就不須要關心線程的問題。咱們在這個類中只作了下邊這幾件事:

  • 開啓下載任務,在開啓任務的start方法中,我作了一些保證任務開始的必要措施,有興趣的能夠去看看源碼
  • 接受數據和寫入數據
  • 處理下載過程當中和完成後的回調函數
  • 處理下載狀態
  • 關心如何取消任務

接下來就到了最核心的地方,如何把MCDownloadReceipt和MCDownloadOperation組合在一塊兒,也就是MCDownloader的內容。MCDownloader是暴露出來最核心的模塊,在設計上主要考慮下邊幾件事情:

  • 須要一個單利對象來管理全局的狀況
  • 支持設置一些跟下載相關的額外信息,好比超時時間,請求頭和併發數等等
  • 提供一些控制下載的經常使用方法,如何開始,取消,移除等等

綜上所述,這基本上是寫任何一個框架的基本流程,在編碼以前先進行設計。 另外,在使用的過程當中,若是有任何問題,能夠給我留言,若是有新的需求,也能夠給我留言。

因爲水平有限,不免會出現錯誤,若是發現後,還望可以告知一聲。

相關文章
相關標籤/搜索