iOS開發(fā)--多圖下載-仿SDWebImage簡單處理

前言

昨天公司有新人過來面試坎怪,統(tǒng)一被問到了這個多圖下載的相關(guān)問題耸携,感覺有一個小伙子回答的挺完善文判,同時感覺有不少朋友在廣泛使用SDWebImage的同時忽略了內(nèi)部的實(shí)現(xiàn)細(xì)節(jié)谈截,所以感覺有必要再次說上一說,希望對大家有所幫助

在實(shí)現(xiàn)多圖下載時我們需要考慮的問題

在我們平時下載圖片的時候都是使用的SDWebImage這個非常牛X的框架芜辕,其實(shí)它內(nèi)部已經(jīng)幫我們做了很多的細(xì)節(jié)處理尚骄,才保證了我們的圖片下載以及顯示包括程序順暢運(yùn)行块差,下面我們就來分析下自己實(shí)現(xiàn)完美的圖片下載會遇到什么問題呢
這里采用tabbleView每一個cell都需要下載顯示圖片為例來說明

1)首先我們需要考慮到圖片的緩存問題侵续,不然每次用戶下載完的圖片離開當(dāng)前頁面再回來就需要重復(fù)下載
  • 圖片緩存第一步倔丈,就需要先弄一個內(nèi)存緩存,也就是自己創(chuàng)建一個數(shù)組状蜗,用來存放已經(jīng)下載下來的圖片
    • 這樣每次用戶上拉需五、下拉或者從其他頁面回來再次顯示圖片的時候不至于重復(fù)下載
  • 而且直接從內(nèi)存緩存里面取的話速度是非常快的轧坎,這樣不會造成卡頓也不會給用戶帶來不好的體驗
  • 圖片緩存第二步宏邮,一個完美的圖片緩存,不可能需要用戶退出程序再次進(jìn)去后再去重新下載之前已經(jīng)下載過的圖片吧缸血,所以我們需要給用戶已經(jīng)下載過的圖片保存到沙盒里面
    • 這里啰嗦的普及一個沙盒文件夾知識蜜氨,就知道我們需要把緩存的圖片放到哪一個文件夾下面了
  1)Documents:
  1-1 該目錄下面的數(shù)據(jù)在連接手機(jī)時會備份
  1-2 蘋果官方不允許把下載的數(shù)據(jù)存放于該目錄下,否則審核直接被拒
  2)Libriary:下面有2個子文件夾
  2-1 caches:存放緩存文件
  2-2 perference:該目錄用來存放偏好設(shè)置如登錄名密碼等等
  3)Tmp
  該文件夾下的文件會被隨時刪除捎泻,所以這個里面最好不要存放用戶的東西
 *** 所以很明顯飒炎,我們需要把圖片存放于caches文件夾下
  • 緊接著就是圖片如何存如何取的問題了,這里先不說圖片的下載笆豁,這是一個麻煩的過程郎汪,所以這里先說存取問題,也就是我們常說的二級緩存
  • 每次圖片需要展示的時候闯狱,首先判斷圖片是否存在于當(dāng)前的內(nèi)存緩存中煞赢,也就是我們創(chuàng)建的存放圖片的數(shù)組,有的話就拿出來顯示
  • 如果數(shù)組里面沒有我們需要顯示的圖片哄孤,那么我們就去沙盒緩存里面去取
    • 如果沙盒緩存有照筑,從沙盒緩存里面取出顯示
    • 然后將其存放于內(nèi)存緩存中,以便在程序不退出的時候用戶再次需要這張圖片的時候快速獲取并顯示
  • 如果沙盒緩存也沒有的話录豺,這個時候就真的需要去網(wǎng)絡(luò)進(jìn)行下載朦肘,下載之后,不僅需要把圖片緩存到沙盒双饥,還需要把圖片保存到內(nèi)存緩存中
2)OK媒抠,解決了圖片緩存之后,那么就需要進(jìn)入最復(fù)雜的情況了咏花,就是如何處理下載圖片的時候產(chǎn)生的各種奇葩的問題
  • 奇葩問題列表
  • 下載圖片實(shí)質(zhì)上屬于耗時操作趴生,耗時操作我們是需要放在子線程中去處理的
  • 我們需要弄一個字典去存放圖片的下載操作,字典的key就使用圖片的url昏翰,本質(zhì)上這個是唯一的苍匆,value自然就是圖片本身了
    • 之所以要使用字典存放圖片的下載操作是因為,萬一用戶網(wǎng)速慢棚菊,這個時候圖片是不會馬上下載完成的浸踩,這個時候用戶萬一上下拖動頁面或者進(jìn)入其他頁面再次回到這個頁面,我們是需要判斷之前的下載操作是否存在的统求,如果存在就不需要再去創(chuàng)建了检碗,等待下載即可据块,如果不存在才需要創(chuàng)建的
  • 還要考慮的就是存在下載操作但是下載失敗的情況,也就是image是空的折剃,這個時候我們需要去移除下載操作另假,以便用戶上拉下拉的時候重新創(chuàng)建下載任務(wù)重新下載圖片,不然下載失敗操作還在怕犁,這樣永遠(yuǎn)都無法重新下載了
  • 下載創(chuàng)建回到主線程刷新UI的時候我們這里不能用tableView的reloadata方法边篮,原因是你如果使用了這個方法,那么用戶在圖片還沒有下載完成的時候上下來回拖動的話奏甫,cell會循環(huán)利用到其他地方戈轿,這樣圖片如果在這個時候下載好,就會把圖片顯示到錯誤的位置阵子,比如本來是第2行的圖片顯示到第5行去了
    • 我們需要采用刷新指定行的方式凶杖,這樣無論你什么時間下載好圖片,你cell再循環(huán)利用款筑,無論當(dāng)前cell是否顯示在屏幕智蝠,我只要在下載好的時候去找到之前的indexPath去刷新,去給image賦值就行了奈梳,都會按照正確的位置去顯示
      [self.tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationMiddle];
  • 完善的下載還需要監(jiān)聽內(nèi)存警告杈湾,在收到內(nèi)存警告的時候移除內(nèi)存緩存,并將這個數(shù)組賦值nil攘须,并且移除下載隊列中的的操作

核心代碼

  • 首先創(chuàng)建一個存放已下載圖片的內(nèi)存緩存字典-- iconsDict
  • 再創(chuàng)建一個存放已創(chuàng)建下載操作的操作字典 -- operationsDict
  • 創(chuàng)建一個非主隊列漆撞,可供全局操作,目的是將下載操作添加到隊列中于宙,讓下載可以異步執(zhí)行 -- downloadQueue
  • iconsDict浮驳、operationsDict、downloadQueue需要多次被訪問到捞魁,需要使用到懶加載最好哦
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:ID ];
    //這里我自己弄了一個模型至会,來給cell內(nèi)部子控件賦值,這里就給賦值操作簡單化了谱俭,沒有使用MVC
    LBApp *model = self.appMarray[indexPath.row];

    cell.textLabel.text = model.name;
    NSString *downloadStr = [NSString stringWithFormat:@"已有%@下載",model.download];
    cell.detailTextLabel.text =downloadStr;

    // 先從內(nèi)存緩存中取出圖片
    UIImage *image = [self.iconsDict objectForKey:model.icon];
    if (image) {// 內(nèi)存中有圖片
        cell.imageView.image = image;
    }else {// 內(nèi)存中沒有圖片
        // 獲得Caches文件夾
         NSString *cachesPath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) firstObject];
        // 獲得文件名
         NSString *filename = [app.icon lastPathComponent];
        // 獲取文件全路徑
         NSString *file = [cachesPath stringByAppendingPathComponent:filename];
        // 加載沙盒的文件數(shù)據(jù)
        NSData *data = [NSData dataWithContentsOfFile:fullPath];
        if (data) {// 直接利用沙盒中圖片
            UIImage *image = [UIImage imageWithData:data];
            cell.imageView.image = image;
            // 存到字典中
            [self.iconsDict setObject:image forKey:model.icon];

        }else {// 沒有的話就下載圖片
            NSBlockOperation *download = nil;
            //顯示占位圖片
            cell.imageView.image = [UIImage imageNamed:@"placeholder"];
            download = self.operationsDict[model.icon];
            if (download) {//如果存在下載操作奉件,什么也不做等待下載

            }else {//創(chuàng)建下載操作
                download = [NSBlockOperation blockOperationWithBlock:^{
                    //加載圖片
                    NSURL *url = [NSURL URLWithString:model.icon];
                    NSData *data = [NSData dataWithContentsOfURL:url];
                    UIImage *image = [UIImage imageWithData:data];
                    if (!image) {//下載失敗
                    //下載失敗移除下載操作,以便用戶上拉下拉的時候重新創(chuàng)建下載任務(wù)重新下載圖片
                        [self.operationsDict removeObjectForKey:model.icon];
                        return ;
                    }
                    //下載成功
                    //image存進(jìn)內(nèi)存緩存,需要先存進(jìn)內(nèi)存然后再去刷新ui昆著,因為刷新ui會重新調(diào)用cellForRow方法县貌,這個時候如果內(nèi)存有圖片,就會直接從內(nèi)存加載然后顯示上去
                    [self.iconsDict setObject:image forKey:model.icon];

                    [[NSOperationQueue mainQueue] addOperationWithBlock:^{//回到主線程刷新UI
                       //刷新指定行
                        [self.tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationMiddle];
                    }];
                    //image數(shù)據(jù)寫入磁盤緩存
                    [data writeToFile:fullPath atomically:YES];
                    //下載完成的時候移除下載操作
                    [self.operationsDict removeObjectForKey:model.icon];
                }];
                //將下載操作添加到隊列中凑懂,讓下載可以異步執(zhí)行
                [self.downloadQueue addOperation:download];
                //將下載操作添加到操作字典中煤痕,防止沒有下載完成上下拖拽的時候重復(fù)創(chuàng)建下載操作
                 self.operationsDict[model.icon] = download;
            }   
        }   
    }
    return cell;
}

結(jié)束語

這里這個大致的思路就說完畢了,大家如果有興趣可以多去研究研究SDWebImage內(nèi)部的實(shí)現(xiàn),對大家的幫助會很大哦摆碉,當(dāng)然存在不完善的地方希望大家可以共同討論學(xué)習(xí)哦祟敛,感謝您花時間閱讀,文字描述較多兆解,但是這些理論性的東西難免如此,非常抱歉

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末跑揉,一起剝皮案震驚了整個濱河市锅睛,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌历谍,老刑警劉巖现拒,帶你破解...
    沈念sama閱讀 210,914評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異望侈,居然都是意外死亡印蔬,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,935評論 2 383
  • 文/潘曉璐 我一進(jìn)店門脱衙,熙熙樓的掌柜王于貴愁眉苦臉地迎上來侥猬,“玉大人,你說我怎么就攤上這事捐韩⊥诉耄” “怎么了?”我有些...
    開封第一講書人閱讀 156,531評論 0 345
  • 文/不壞的土叔 我叫張陵荤胁,是天一觀的道長瞧预。 經(jīng)常有香客問我,道長仅政,這世上最難降的妖魔是什么垢油? 我笑而不...
    開封第一講書人閱讀 56,309評論 1 282
  • 正文 為了忘掉前任,我火速辦了婚禮圆丹,結(jié)果婚禮上滩愁,老公的妹妹穿的比我還像新娘。我一直安慰自己辫封,他們只是感情好惊楼,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,381評論 5 384
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著秸讹,像睡著了一般檀咙。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上璃诀,一...
    開封第一講書人閱讀 49,730評論 1 289
  • 那天弧可,我揣著相機(jī)與錄音,去河邊找鬼劣欢。 笑死棕诵,一個胖子當(dāng)著我的面吹牛裁良,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播校套,決...
    沈念sama閱讀 38,882評論 3 404
  • 文/蒼蘭香墨 我猛地睜開眼价脾,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了笛匙?” 一聲冷哼從身側(cè)響起侨把,我...
    開封第一講書人閱讀 37,643評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎妹孙,沒想到半個月后秋柄,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,095評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡蠢正,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,448評論 2 325
  • 正文 我和宋清朗相戀三年骇笔,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片嚣崭。...
    茶點(diǎn)故事閱讀 38,566評論 1 339
  • 序言:一個原本活蹦亂跳的男人離奇死亡笨触,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出雹舀,到底是詐尸還是另有隱情旭旭,我是刑警寧澤,帶...
    沈念sama閱讀 34,253評論 4 328
  • 正文 年R本政府宣布葱跋,位于F島的核電站持寄,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏娱俺。R本人自食惡果不足惜稍味,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,829評論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望荠卷。 院中可真熱鬧模庐,春花似錦、人聲如沸油宜。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,715評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽慎冤。三九已至疼燥,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間蚁堤,已是汗流浹背醉者。 一陣腳步聲響...
    開封第一講書人閱讀 31,945評論 1 264
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人撬即。 一個月前我還...
    沈念sama閱讀 46,248評論 2 360
  • 正文 我出身青樓立磁,卻偏偏與公主長得像,于是被迫代替她去往敵國和親剥槐。 傳聞我的和親對象是個殘疾皇子唱歧,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,440評論 2 348

推薦閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 171,730評論 25 707
  • 前不久做了一個生成快照的需求,其中用到 SDWebImage 來下載圖片粒竖,在使用該框架的過程中也遇到了一些問題颅崩,索...
    ShannonChenCHN閱讀 14,056評論 12 241
  • *面試心聲:其實(shí)這些題本人都沒怎么背,但是在上海 兩周半 面了大約10家 收到差不多3個offer,總結(jié)起來就是把...
    Dove_iOS閱讀 27,128評論 29 470
  • 我的愛如一朵花開 安靜地綻放在時間之外 親愛的媽媽啊 我不能時時陪伴在您身旁 只能讓美麗的康乃馨來替代 我的愛如一...
    簡JN閱讀 315評論 5 10
  • 其實(shí),許多事從一開始就已料到了結(jié)局温圆,往后所有的折騰,都不過只是為了拖延散場的時間 孩革。
    Luke米兒閱讀 153評論 0 0