優(yōu)秀iOS三方框架解析二(SDWebImage)

一屡谐、功能簡(jiǎn)介:

1.一個(gè)添加了web圖片加載和緩存管理的UIImageView分類

2.一個(gè)異步圖片下載器

3.一個(gè)異步的內(nèi)存加磁盤綜合存儲(chǔ)圖片并且自動(dòng)處理過期圖片

4.支持動(dòng)態(tài)gif圖

5.支持webP格式的圖片

5.后臺(tái)圖片解壓處理

6.確保同樣的圖片url不會(huì)下載多次

7.確保偽造的圖片url不會(huì)重復(fù)嘗試下載

8.確保主線程不會(huì)阻塞

二娘纷、SDWebImage 加載圖片的流程

1.入口 setImageWithURL:placeholderImage:options:會(huì)先把 placeholderImage顯示,然后 SDWebImageManager 根據(jù) URL 開始處理圖片

2.進(jìn)入 SDWebImageManager-downloadWithURL:delegate:options:userInfo:,交給 SDImageCache 從緩存查找圖片是否已經(jīng)下載 queryDiskCacheForKey:delegate:userInfo:

  • 先從內(nèi)存圖片緩存查找,如果內(nèi)存中已經(jīng)有圖片緩存,SDImageCacheDelegate 回調(diào) imageCache:didFindImage:forKey:userInfo:SDWebImageManager
  • SDWebImageManagerDelegate 回調(diào) webImageManager:didFinishWithImage:UIImageView+WebCache 等前端展示圖片
  • 如果內(nèi)存緩存中沒有,生成 NSInvocationOperation 添加到隊(duì)列開始從硬盤查找圖片是否已經(jīng)緩存

3.根據(jù) URLKey 在硬盤緩存目錄下嘗試讀取圖片文件因妙。這一步是在 NSOperation 進(jìn)行的操作,所以回主線程進(jìn)行結(jié)果回調(diào) notifyDelegate:
如果上一操作從硬盤讀取到了圖片票髓,將圖片添加到內(nèi)存緩存中(如果空閑內(nèi)存過小攀涵,會(huì)先清空內(nèi)存緩存)。SDImageCacheDelegate 回調(diào) imageCache:didFindImage:forKey:userInfo:洽沟;進(jìn)而回調(diào)展示圖片
4.如果從硬盤緩存目錄讀取不到圖片以故,說明所有緩存都不存在該圖片,需要下載圖片玲躯,回調(diào) imageCache:didNotFindImageForKey:userInfo:

5.共享或重新生成一個(gè)下載器 SDWebImageDownloader 開始下載圖片

6.connectionDidFinishLoading:數(shù)據(jù)下載完成后交給 SDWebImageDecoder做圖片解碼處理

7.圖片解碼處理在一個(gè) NSOperationQueue 完成据德,不會(huì)拖慢主線程 UI。如果有需要對(duì)下載的圖片進(jìn)行二次處理跷车,可以在這里完成棘利,效率會(huì)好很多。
8.在主線程 notifyDelegateOnMainThreadWithInfo:宣告解碼完成朽缴,imageDecoder:didFinishDecodingImage:userInfo: 回調(diào)給 SDWebImageDownloader
imageDownloader:didFinishWithImage: 回調(diào)給 SDWebImageManager 告知圖片下載完成

8.通知所有的 downloadDelegates 下載完成善玫,回調(diào)給需要的地方展示圖片

9.將圖片保存到 SDImageCache 中,內(nèi)存緩存和硬盤緩存同時(shí)保存密强。寫文件到硬盤也在以單獨(dú) NSInvocationOperation 完成茅郎,避免拖慢主線程

三、圖片緩存策略: (不緩存或渤,內(nèi)存緩存系冗,沙盒緩存)

SDImageCache是怎么做數(shù)據(jù)管理的?

  • SDImageCache分兩個(gè)部分薪鹦,一個(gè)是內(nèi)存層面的掌敬,一個(gè)是硬盤層面的惯豆。

  • 內(nèi)存層面的相當(dāng)是個(gè)緩存器,以Key-Value的形式存儲(chǔ)圖片奔害。當(dāng)內(nèi)存不夠的時(shí)候會(huì)清除所有緩存圖片楷兽。

  • 用搜索文件系統(tǒng)的方式做管理,文件替換方式是以時(shí)間為單位华临,剔除時(shí)間大于一周的圖片文件

  • 當(dāng)SDWebImageManager向SDImageCache要資源時(shí)芯杀,先搜索內(nèi)存層面的數(shù)據(jù),如果有直接返回雅潭,沒有的話去訪問磁盤揭厚,將圖片從磁盤讀取出來,然后做Decoder寻馏,將圖片對(duì)象放到內(nèi)存層面做備份棋弥,再返回調(diào)用層。

  1. memory cache
@interface SDImageCache ()
#pragma mark - Properties
@property (strong, nonatomic, nonnull) NSCache *memCache;
// 這里我們發(fā)現(xiàn)诚欠, 有一個(gè)叫做 memCache 的屬性,它是一個(gè) NSCache 對(duì)象漾岳,用于實(shí)現(xiàn)我們對(duì)圖片的 Memory Cache轰绵。
// NSCache 簡(jiǎn)單來說,它是一個(gè)類似于 NSDictionary 的集合類尼荆,用于在內(nèi)存中存儲(chǔ)我們要緩存的數(shù)據(jù)左腔。詳細(xì)信息大家可以參考官方文檔:https://developer.apple.com/reference/foundation/nscache
/ 接受系統(tǒng)的內(nèi)存警告通知,然后清除掉自身的圖片緩存
@interface AutoPurgeCache : NSCache
@end
@implementation AutoPurgeCache
- (nonnull instancetype)init {
    self = [super init];
    if (self) {
#if SD_UIKIT
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(removeAllObjects) name:UIApplicationDidReceiveMemoryWarningNotification object:nil];
#endif
    }
    return self;
}

2.Disk Cache:
也就是文件緩存捅儒,SDWebImage 會(huì)將圖片存放到 NSCachesDirectory 目錄中液样,然后為每一個(gè)緩存文件生成一個(gè) md5 文件名, 存放到文件中。

3.Disk 緩存清理策略
SDWebImage 會(huì)在每次 APP 結(jié)束和程序切到后臺(tái)的時(shí)候執(zhí)行清理任務(wù)巧还。 清理緩存的規(guī)則分兩步進(jìn)行鞭莽。 第一步先清除掉過期的緩存文件。 如果清除掉過期的緩存之后麸祷,空間還不夠澎怒。 那么就繼續(xù)按文件時(shí)間從早到晚排序,先清除最早的緩存文件阶牍,直到剩余空間達(dá)到要求喷面。

具體點(diǎn),SDWebImage 是怎么控制哪些緩存過期走孽,以及剩余空間多少才夠呢惧辈? 通過兩個(gè)屬性:

@interface SDImageCache : 
NSObject@property (assign, nonatomic) NSInteger maxCacheAge;//文件緩存的時(shí)長(zhǎng)
@property (assign, nonatomic) NSUInteger maxCacheSize;//允許的最大緩存空間

//  maxCacheAge 的默認(rèn)值
static const NSInteger kDefaultCacheMaxCacheAge = 60 * 60 * 24 * 7; // 1 week
// maxCacheSize 的默認(rèn)值
[SDImageCache sharedImageCache].maxCacheSize = 1024 * 1024 * 50;  // 50M

四、圖片Decoder

Q: 為什么要進(jìn)行圖片Decoder磕瓷?
A: png,jpeg等格式的數(shù)據(jù)是不能直接使用的,需要將其轉(zhuǎn)化為位圖(bitMap)
SDWebImage部份可以參考:+ (nullable UIImage *)decodedAndScaledDownImageWithImage:(nullable UIImage *)image函數(shù)

Q: imageView 加載一張圖片的過程 ?
A:
當(dāng)我們使用imageView顯示圖片的時(shí)候:

  • 讀取圖片
  • 解壓圖片為位圖(消耗CPU)
  • 如果位圖數(shù)據(jù)不是字節(jié)對(duì)齊的盒齿,CoreAnimation會(huì)copy一份位圖數(shù)據(jù)并進(jìn)行字節(jié)對(duì)齊
  • CoreAnimation渲染解壓縮過的位圖
  • 這一切在IOS中都是默認(rèn)發(fā)生在主線程成的并且是在UIImageView執(zhí)行setImage方法的時(shí)候完成的

總結(jié):

其實(shí)不解碼也是可以使用的,假如說我們通過imageNamed:來加載image,系統(tǒng)默認(rèn)會(huì)在主線程立即進(jìn)行圖片的解碼工作县昂。這一過程就是把image解碼成可供控件直接使用的位圖肮柜。
當(dāng)在主線程調(diào)用了大量的imageNamed:方法后,就會(huì)產(chǎn)生卡頓了倒彰。為了解決這個(gè)問題我們有兩種比較簡(jiǎn)單的處理方法:
1.我們不使用imageNamed:加載圖片审洞,使用其他的方法,比如imageWithContentsOfFile:
2.我們自己解碼圖片待讳,可以把這個(gè)解碼過程放到子線程

好處:

  • 把圖片解碼這個(gè)默認(rèn)在主線程執(zhí)行,耗損CPU的行為,放在了后臺(tái)線程.
  • 只需要在使用的時(shí)候,直接setImage,不會(huì)有太大的CPU消耗

弊端:

  • 這樣解碼就是以空間換時(shí)間的方法,提前解壓好,用的時(shí)候直接從內(nèi)存讀取.
  • 如果下載的圖片比較大,然后直接解碼的話 這個(gè)是內(nèi)存所不能承受,需要對(duì)圖片進(jìn)行壓縮.

補(bǔ)充些其他的

  • +(nullableUIImage*)imageNamed:(NSString*)name:不適合加載大的 不常用的圖片.因?yàn)樗鼤?huì)默認(rèn)在程序內(nèi)存里保存這張圖片數(shù)據(jù)(不會(huì)隨ImageView的移除而移除).只有經(jīng)常使用圖片適合這種方式加載.
  • + (nullableUIImage*)imageWithContentsOfFile:(NSString*)path:這個(gè)方法跟上面的略有不同,他不會(huì)在內(nèi)存中保留一份數(shù)據(jù).只要imageView移除,內(nèi)存中的數(shù)據(jù)就會(huì)直接移除.這也就是這個(gè)方法為什么適合加載大的圖片,但卻不常用的圖片.
  • 相關(guān)的參考文章:IOS異步圖片加載與常用的優(yōu)化
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末芒澜,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子创淡,更是在濱河造成了極大的恐慌痴晦,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,482評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件琳彩,死亡現(xiàn)場(chǎng)離奇詭異誊酌,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)露乏,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,377評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門碧浊,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人瘟仿,你說我怎么就攤上這事箱锐。” “怎么了劳较?”我有些...
    開封第一講書人閱讀 152,762評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵驹止,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我观蜗,道長(zhǎng)臊恋,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,273評(píng)論 1 279
  • 正文 為了忘掉前任嫂便,我火速辦了婚禮捞镰,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘毙替。我一直安慰自己岸售,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,289評(píng)論 5 373
  • 文/花漫 我一把揭開白布厂画。 她就那樣靜靜地躺著凸丸,像睡著了一般。 火紅的嫁衣襯著肌膚如雪袱院。 梳的紋絲不亂的頭發(fā)上屎慢,一...
    開封第一講書人閱讀 49,046評(píng)論 1 285
  • 那天瞭稼,我揣著相機(jī)與錄音,去河邊找鬼腻惠。 笑死环肘,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的集灌。 我是一名探鬼主播悔雹,決...
    沈念sama閱讀 38,351評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼欣喧!你這毒婦竟也來了腌零?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,988評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤唆阿,失蹤者是張志新(化名)和其女友劉穎益涧,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體驯鳖,經(jīng)...
    沈念sama閱讀 43,476評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡闲询,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,948評(píng)論 2 324
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了浅辙。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片嘹裂。...
    茶點(diǎn)故事閱讀 38,064評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖摔握,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情丁寄,我是刑警寧澤氨淌,帶...
    沈念sama閱讀 33,712評(píng)論 4 323
  • 正文 年R本政府宣布,位于F島的核電站伊磺,受9級(jí)特大地震影響盛正,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜屑埋,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,261評(píng)論 3 307
  • 文/蒙蒙 一豪筝、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧摘能,春花似錦续崖、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,264評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至逻恐,卻和暖如春像吻,著一層夾襖步出監(jiān)牢的瞬間峻黍,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,486評(píng)論 1 262
  • 我被黑心中介騙來泰國(guó)打工拨匆, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留姆涩,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,511評(píng)論 2 354
  • 正文 我出身青樓惭每,卻偏偏與公主長(zhǎng)得像骨饿,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子洪鸭,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,802評(píng)論 2 345

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