做iOS開發(fā)3年了,基本上常用的庫(kù)的源碼都有看過(guò). 突然想起來(lái)SDWebImage的源碼還沒(méi)看過(guò),一方面是SD常用到,但是幾乎不會(huì)對(duì)其進(jìn)行擴(kuò)展和修改,另一方面是對(duì)原理很清楚明了,計(jì)算機(jī)三級(jí)緩存結(jié)構(gòu)嘛. 這就有點(diǎn)燈下黑了,還是有很多的細(xì)節(jié)值得學(xué)習(xí)的. 趁有時(shí)間,把SD源碼閱讀一下,并做下總結(jié).
SD原理
計(jì)算機(jī)的存儲(chǔ)系統(tǒng),根據(jù)材質(zhì)和功能,可分為三個(gè)結(jié)構(gòu)
- 外存: 確保計(jì)算機(jī)有較大的存儲(chǔ)容量. 一般為U盤,硬盤等.
- 內(nèi)存:也就是我們常說(shuō)的運(yùn)存,存儲(chǔ)運(yùn)行時(shí)期的數(shù)據(jù), 確保cpu對(duì)數(shù)據(jù)的快速讀取.
- cache:內(nèi)存的存取速度,不能匹配cpu的處理速度,cache的目的在于進(jìn)一步強(qiáng)化cpu對(duì)數(shù)據(jù)的讀取速度.
cpu在讀取數(shù)據(jù)時(shí),會(huì)先去cache中查找數(shù)據(jù),如果cache中沒(méi)有,就會(huì)去內(nèi)存乃至外存中查找. 查找過(guò)后,內(nèi)存和cache中會(huì)緩存一份數(shù)據(jù),當(dāng)cpu下次再讀取同一份數(shù)據(jù)時(shí),就可以直接從cache中讀取.
SDWebimage在對(duì)圖片的存儲(chǔ)上,使用了類似的結(jié)構(gòu)
使用SD時(shí),SD會(huì)先從Cache中查找圖片是否緩存,如果找到,就return image. 如果cache中沒(méi)有該圖片,就去Disk中查找.同理,如果Disk中也沒(méi)有該圖片,就會(huì)從遠(yuǎn)程服務(wù)器下載該圖片并做對(duì)應(yīng)的緩存.
SD代碼結(jié)構(gòu)
UIImageView/UIButton的category,提供各個(gè)控件的使用SD的便捷API. UIView的category提供各個(gè)子視圖的公共方法.
各個(gè)category最總會(huì)將URL傳遞至
SDWebImageManager
,SDWebImageManager
是SD的中樞,聚合SDImageCache
,SDImageDownloader
等. 對(duì)外提供接口 ,對(duì)內(nèi)管理緩存,下載等功能.SDImageCache
. 提供cache緩存,硬盤緩存的功能. 管理SDMemoryCache
,Disk,緩存的相關(guān)配置SDImageCacheConfig
以及IO隊(duì)列SDWebImageDownloader
提供圖片下載的功能,管理下載Session,下載隊(duì)列(_downloadQueue),網(wǎng)絡(luò)安全校驗(yàn)等.SDWebImageCodersManager
,提供圖片的編解碼功能, 接口由SDWebImageCoder
定義,實(shí)現(xiàn)由SDWebImageImageIOCoder
,SDWebImageGIFCoder
,SDWebImageWebPCoder
等完成.
閃光的細(xì)節(jié).
- 宏定義
dispatch_queue_async_safe
. 判斷當(dāng)前隊(duì)列與傳入隊(duì)列是否相同,如果相同,直接執(zhí)行block,如果不同,再去指定隊(duì)列一步的調(diào)用block.
#ifndef dispatch_queue_async_safe
#define dispatch_queue_async_safe(queue, block)\
if (dispatch_queue_get_label(DISPATCH_CURRENT_QUEUE_LABEL) == dispatch_queue_get_label(queue)) {\
block();\
} else {\
dispatch_async(queue, block);\
}
#endif
#ifndef dispatch_main_async_safe
#define dispatch_main_async_safe(block) dispatch_queue_async_safe(dispatch_get_main_queue(), block)
#endif
- 使用信號(hào)量實(shí)現(xiàn)資源鎖,初始化信號(hào)計(jì)數(shù)為1,當(dāng)信號(hào)>=1時(shí),減去1并執(zhí)行任務(wù)而不等待,反之則等待信號(hào).
#define LOCK(lock) dispatch_semaphore_wait(lock, DISPATCH_TIME_FOREVER);
#define UNLOCK(lock) dispatch_semaphore_signal(lock);
--
self.weakCacheLock = dispatch_semaphore_create(1);
---
LOCK(self.weakCacheLock);
[self.weakCache setObject:obj forKey:key];
UNLOCK(self.weakCacheLock);
- 使用位移運(yùn)算符,以及位運(yùn)算符&,|來(lái)控制option,具有速度快,并且統(tǒng)一可以將多個(gè)選項(xiàng)放在同一數(shù)值中表示.
typedef NS_OPTIONS(NSUInteger, SDImageCacheOptions) {
SDImageCacheQueryDataWhenInMemory = 1 << 0,
SDImageCacheQueryDiskSync = 1 << 1,
SDImageCacheScaleDownLargeImages = 1 << 2
};
相關(guān)延伸知識(shí)
GCD相關(guān)知識(shí)
@autoreleasepool
@synchronized