iOS請求緩存、離線緩存 框架 ZBNetworking

  • 在最初接觸數據緩存的時候 就看到多個博客提到能夠用SDWebImage緩存圖片方式的思路去作數據緩存,但是基本沒有看到去實踐的,而更多看到的使用sqlite的封裝FMDB去作緩存,也有用系統的NSURLCache,可表現的都很難擴展,對請求緩存中的一些操做都很單一。也許我沒看到好的吧,若是有請留言給我謝謝。
  • 先說說一些緩存中的 誤區:看到不少剛接觸緩存這塊的開發者認爲 網絡狀態是緩存的第一判斷條件,大概是有網絡就從新請求數據,無網絡就使用緩存。這麼認爲的就是進入誤區了。就說一個例子,有網絡,但服務器掛了,怎麼辦。顯示你返回請求失敗的異常頁面嗎?有人說了 請求失敗再使用緩存唄。我們作APP的 是否是要考慮用戶的使用體驗啊。請求失敗了,都啥時候了,黃花菜都涼了。
  • 你們能夠看看幾個主流APP 的緩存顯示方式「 網易新聞」,「今日頭條」,「 微博」 。在有緩存的狀態下, 這幾款APP都是 優先顯示緩存,同時有的進行自動下拉刷新操做,有的給你提示,有多少條數據更新,請進行下拉刷新操做 。下拉刷新就是重現請求,請求的結果有不少狀態,與界面操做有關就幾種,請求成功替換顯示的數據,請求超時給提示,請求失敗給提示。能夠看出 緩存是和請求分不開的(因爲GET請求通常用來查詢數據,POST請求通常是發大量數據給服務器處理(變更性比較大)所以通常只對GET請求進行緩存,而不對POST請求進行緩存)。
  • 正確的緩存的使用策略 是在有緩存的狀態下,使用緩存,沒有緩存去請求,請求的成功後的數據刷新界面,並覆蓋原緩存文件。結合網絡請求,還要給出不使用緩存的狀態,和使用緩存的狀態.在實際運用中能夠能還有別的需求,好比上拉加載的狀態,離線緩存的狀態,因此請求的種類多樣,緩存的使用策略的狀態也要多樣。
  • 根據此緩存策略 封裝的 請求框架 ZBNetworking

ZBNetworking

優勢: 1 低耦合,易擴展。(這個下篇文章體現) 2.有緩存文件過時機制 默認一週(以最後緩存文件修改時間爲準) 3.顯示緩存大小/個數,所有清除緩存/單個文件清除緩存/按時間清除緩存 方法多樣 而且均可以自定義路徑 可擴展性強 4.離線下載功能 5.多種請求類型的判斷。也可不遵循,自由隨你定。git

/** 從新請求 ,不讀取緩存,從新請求*/
    ZBRequestTypeRefresh,
    /** 有緩存,讀取緩存 無緩存,從新請求*/
    ZBRequestTypeCache,
    /** 加載更多 ,不讀取緩存,從新請求*/
    ZBRequestTypeRefreshMore,
    /** 加載更多 ,有緩存,讀取緩存 無緩存,從新請求*/
    ZBRequestTypeCacheMore,
    /** 詳情    ,有緩存,讀取緩存 無緩存,從新請求*/
    ZBRequestTypeDetailCache,
    /** 自定義  ,有緩存,讀取緩存 無緩存,從新請求*/
    ZBRequestTypeCustomCache
複製代碼

6.可見的緩存文件 github

ZBNetworking_cache_gif.gif

AFNetworking 很少介紹了 在使用OC開發的,不少都用這個。封裝了一個緩存管理類ZBCacheManager,主要參照了SDWebImage的SDImageCache磁盤存儲的思路,SDWebImage的存儲性能你們應該不用懷疑,但也要進行大量的改動,畢竟SDImageCache 只是緩存圖片的。無論用那種請求方法 緩存文件都會存儲到沙盒 /Library/Caches/ZBKit/AppCache 路徑下 。 有一點要注意,請求下來的數據格式 是二進制的 由於緩存也是二進制數據 。因此設置了responseSerializer = [AFHTTPResponseSerializer serializer];不能更改。sql

  • 運行流程以下圖

F0C2D948-9691-40B5-8251-554FB85A84EA.png

請求示例 具體看demo 。 2017-8-21 重構了此庫 如今默認爲Refresh (從新請求,不讀緩存)。json

[ZBRequestManager requestWithConfig:^(ZBURLRequest *request){
        request.urlString=list_URL;
        request.methodType=ZBMethodTypeGET;//默認爲GET
        request.apiType=ZBRequestTypeCache;//默認爲ZBRequestTypeRefresh
    }  success:^(id responseObj,apiType type){
        if (type==ZBRequestTypeRefresh) {
              //下拉結束刷新
        }  
        if (type==ZBRequestTypeLoadMore) {
            // 上拉結束刷新
        }
             //請求成功
        
    } failed:^(NSError *error){
        if (error.code==NSURLErrorCancelled)return;
        if (error.code==NSURLErrorTimedOut){
            [self alertTitle:@"請求超時" andMessage:@""];
        }else{
            [self alertTitle:@"請求失敗" andMessage:@""];
        }
    }];

//取消對應的網絡請求
 [ZBRequestManager cancelRequest: list_URL completion:^(NSString *urlString){
        //若是請求成功 或 讀緩存 會返回null 沒法取消。請求未完成的會取消並返回對應url
        //NSLog(@"取消對應url:%@ ",urlString);
    }];
複製代碼
  • 其餘的一些功能 顯示緩存大小 ,緩存個數。按時間清除緩存,手動清理緩存,自定義清除某個路徑文件,清除某個單獨key的緩存等功能,
    9075F331-0F70-44B8-8405-E067D1EE0A28.png

#離線緩存/下載api

  • 下面要說離線緩存功能。不知道該功能的:能夠下個今日頭條/個人 /離線 功能看看 通常新聞類的APP 大多有該功能。 要作離線緩存功能:必需要有先決條件,就是必定不要多個緩存路徑 ,特別是圖片的緩存功能,存儲路徑要統一。個人demo中圖片請求如今使用的是SDWebImage,其實也能夠用別的。只要你用的圖片請求框架 在數據列表顯示的圖片 和 在離線下載 的圖片 用的是一個緩存就能夠,SDWebImage 由於用了MD5編碼,確保了每一個URL對應的緩存惟一性。這裏有個問題,有不少應用有輪播視圖的功能 ,而大多數封裝好輪播都是本身進行請求並緩存到自定義的緩存路徑,這個要處理一下,這裏我選用了一個codingZero 大神 XRCarouselView 的輪播視圖進行修改,(爲何選擇這個,由於他寫好簡單,代碼好少,好修改)。 先把其餘的請求/建立/存儲緩存方法都刪掉 而後找到 - (void)downloadImages:(int)index 方法 進行修改
//使用SDWebImage方法替換內部實現
- (void)downloadImages:(int)index {
    
    [[SDWebImageManager sharedManager] downloadImageWithURL:[NSURL URLWithString:_imageArray[index]] options:0 progress:^(NSInteger receivedSize, NSInteger expectedSize){
        
    } completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType,BOOL finished,NSURL *imageURL){
        if (image) {
            self.images[index] = image;
            //若是下載的圖片爲當前要顯示的圖片,直接到主線程給imageView賦值,不然要等到下一輪纔會顯示
            if (_currIndex == index) [_currImageView performSelectorOnMainThread:@selector(setImage:) withObject:image waitUntilDone:NO];
        }
    }];
}

複製代碼

C2A147C7-8F29-490F-82CE-62810491A150.png

好了 咱們的列表圖片包括輪播圖片 緩存 都在SDWebImage 的默認緩存路徑裏了,由於XRCarouselView 我並無徵得做者的贊成更改,因此demo中就不使用了,主要讓你們 知道 圖片的請求與存儲要統一 而咱們的json 數據 已經緩存到/Library/Caches/ZBKit/AppCache 路徑下 。下面開始 實現離線功能數組

  • 其實離線緩存並非一個 高深的技術,仍是緩存。正常咱們瀏覽一個頁面緩存這個頁面的數據。而離線就是同時請求多個頁面並緩存下來。
    F7B3FE2C-FE73-4D9E-A394-104C22FAA391.png

思路就是 每一個頻道就是一個url,把你要緩存的 url 放到一個數組裏 進行遍歷請求。ZBRequestManager已經封裝好了 離線的方法緩存

- (void)requestOffline:(NSMutableArray *)offlineArray{

    [ZBRequestManager sendBatchRequest:^(ZBBatchRequest *batchRequest){
         for (NSString *urlString in offlineArray) {
            ZBURLRequest *request=[[ZBURLRequest alloc]init];
            request.urlString=urlString;
            [batchRequest.urlArray addObject:request];
        }
    }  success:^(id responseObj,apiType type){

            NSLog(@"添加了幾個url請求 就會走幾遍");
            NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:responseObj options:NSJSONReadingMutableContainers error:nil];
            NSArray *array=[dict objectForKey:@"videos"];
            for (NSDictionary *dic in array) {
                DetailsModel *model=[[DetailsModel alloc]init];
                model.thumb=[dic objectForKey:@"thumb"]; //找到圖片的key
                [self.imageArray addObject:model];
                
                //使用SDWebImage 下載圖片
                BOOL isKey=[[SDImageCache sharedImageCache]diskImageExistsWithKey:model.thumb];
                if (isKey) {
                    self.offlineView.progressLabel.text=@"已經下載了";
                } else{
                    
                    [[SDWebImageManager sharedManager] downloadImageWithURL:[NSURL URLWithString:model.thumb] options:0 progress:^(NSInteger receivedSize, NSInteger expectedSize){
                        
                        NSLog(@"%@",[self progressStrWithSize:(double)receivedSize/expectedSize]);
                        
                        self.offlineView.progressLabel.text=[self progressStrWithSize:(double)receivedSize/expectedSize];
                        
                        self.offlineView.pv.progress =(double)receivedSize/expectedSize;
                        
                    } completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType,BOOL finished,NSURL *imageURL){
                        
                        NSLog(@"單個圖片下載完成");
                        self.offlineView.progressLabel.text=nil;
                        
                        self.offlineView.progressLabel.text=[self progressStrWithSize:0.0];
                        
                        self.offlineView.pv.progress = 0.0;
                        
                        [self.tableView reloadData];
                        //讓 下載的url與模型的最後一個比較,若是相同證實下載完畢。
                        NSString *imageURLStr = [imageURL absoluteString];
                        NSString *lastImage=[NSString stringWithFormat:@"%@",((DetailsModel *)[self.imageArray lastObject]).thumb];
                        
                        if ([imageURLStr isEqualToString:lastImage]) {
                            NSLog(@"下載完成");
                            
                            [self.offlineView hide];//取消下載進度視圖
                            [self alertTitle:@"下載完成"andMessage:@""];
                             self.imageArray=nil;
                        }
                        
                        if (error) {
                            NSLog(@"下載失敗");
                        }
                    }];
                    
                }
                
            }

    } failed:^(NSError *error){
        if (error.code==NSURLErrorCancelled)return;
        if (error.code==NSURLErrorTimedOut){
            [self alertTitle:@"請求超時" andMessage:@""];
        }else{
            [self alertTitle:@"請求失敗" andMessage:@""];
        }
    }];
}
複製代碼

cache

點擊 Github地址 下載bash

結尾:水平有限,代碼也很爛,一直在努力學習中,你們多多包涵。若是你喜歡這個輪子,請給個star,這是對做者最大的鼓勵和支持,拜謝!!!假如你有更好的想法或方案請留言!服務器

下篇文章:設計一個簡單的圖片緩存器 網絡

相關文章
相關標籤/搜索