SDWebImage

主要引用

目錄

1. ??

<1> SDWebImageCompat

.h? --? 兼容(GC+Version+UI+NS_ENUM_OPTIONS+屬性語義&內(nèi)存管理+保持主線程執(zhí)行block的宏)?

.m? -- ?inline SDScaledImageForKey ?-> ?i. 所有圖片設(shè)置對應(yīng)scale ?ii. 動畫圖片返回

<2> SDWebImageOperation

@protocol ?SDWebImageOperation ?-- ?-cancel


2. ?

<1> SDWebImageDownloader ?-- ?是對operationQueue的一層封裝

.h?

-- ?SDWebImageDownloaderOptions(8) + SDWebImageDownloaderExecutionOrder(2)?

--? Start/StopNotification + Progress/CompletedBlock + HeadersFilterBlock

-- ?+sharedDownloader ,? -downloadImageWithURL:~~

.m??

-- ?+initialize(SDNetworkActivityIndicator) ,+sharedDownloader , -init(init+webp)

--? HTTPHeaders的getter&setter + 最大和當前并發(fā)數(shù)返回queue的,暫停隊列等

--? downloadImageWithURL:( request -> operation(init:progress:復(fù)制URLCallbacks[url] + 異步主隊列遍歷-調(diào)用其中progressBlock,completed:barrier_sync(復(fù)制+完成移除)+ 遍歷-調(diào)用其中completedBlock,cancelled:barrier_async(移除))+證書+隊列優(yōu)先級+operation入queue ) <- addProgressCallback:(dispatch_barrier_sync(封裝block )做阻塞)

Tips:

i.? NSURLRequest / NSMutableURLRequest

url + NSURLRequestCachePolicy + timeoutInterval && NSURLRequestNetworkServiceType

ii.? NSURLRequest (NSHTTPURLRequest)/ NSMutableURLRequest (NSMutableHTTPURLRequest)

allHTTPHeaderFields + HTTPBody

iii.? NSURLCredential ?-- ?NSURLCredentialPersistence

NSURLCredential(NSInternetPassword)


<2> SDWebImageDownloaderOperation? --? 是對Operation的一層封裝(繼承Operation實踐)

標配:

-start:(檢查取消,后臺運行(expirationBlock:停止runloop,stop通知,executing,finished,觸發(fā)start通知,開啟runloop用于調(diào)用NSURLConnection的Delegate)

手動觸發(fā) _finished & _executing的KVO

-isConcurrent

.h ?-- ?Start/Stop/Finish/ReceiveResponse通知 + -initWithRequest:~~

.m ?-- ?init

-- ?NSURLConnectionDelegate:

~~: didReceiveData:

connectionDidFinishLoading:

didFailWithError:

willCacheResponse: ?-- ?這里返回nil,responses將不會緩存,詳參 NSURLCache

willSendRequestForAuthChallenge:


3.?

<1> SDImageCache

.h?

--? SDImageCacheType + Query/CheckCacheCompletedBlock/CalculateSizeBlock

--? +sharedImageCache

initWithNamespace:diskCacheDirectory:

makeDiskCachePath:(NSCachesDirectory緩存目錄),

addReadOnlyCachePath:(懶加載+不包含添加),storeImage:recalculateFromImage:imageData:forKey:toDisk:,queryDiskCacheForKey:done:,imageFromMemoryCacheForKey:

imageFromDiskCacheForKey:(給key,查找內(nèi)存和磁盤(ifNeed,內(nèi)存緩存(NSCache)),返回)

removeImageForKey:fromDisk:withCompletion:

clearMemory,clearDiskOnCompletion:,cleanDiskWithCompletionBlock:

calculateSizeWithCompletionBlock(拿size和cnt丟到block中)

diskImageExistsWithKey:(fileExistsAtPath)/completion: 異步串行隊列(fileExistsAtPath +異步主隊列completionBlock)

cachePathForKey:inPath:(緩存路徑(diskCachePath/自定義Path + MD5的filename))

.m ?-- ?

AutoPurgeCache?

-- init: UIApplicationDidReceiveMemoryWarningNotification -removeAllObjects,dealloc: remove

ImageDataHasPNGPreffix,SDCacheCostForImage (像素數(shù))

initWithNamespace:diskCacheDirectory: (各種初始化+3通知)

storeImage:recalculateFromImage:imageData:forKey:toDisk: ( 內(nèi)存緩存,磁盤緩存(異步串行隊列(i.判斷PNG_JPEG->data ii.緩存目錄+緩存路徑->緩存文件+禁止iCloud備份)) )

diskImageDataBySearchingAllPathsForKey: 緩存路徑Data(diskCachePath) +自定義路徑Data(customPaths)

diskImageForKey: (所有路徑找data->image->scale調(diào)整->提前解碼)

queryDiskCacheForKey:done: (給key-查找內(nèi)存(doneBlock)和磁盤(ifNeed,內(nèi)存緩存(NSCache)+doneBlock)-返回operation)

removeImageForKey:fromDisk:withCompletion: (remove內(nèi)存緩存+ remove磁盤緩存(removeItemAtPath: +異步主隊列completion()) )

clearDiskOnCompletion: (異步串行(remove->create緩存目錄+異步主隊列completion()))

cleanDiskWithCompletionBlock: (目錄枚舉器(diskCacheDictionaryURL + resourceKeys) ->移除過期URLs,超出最大內(nèi)存清理為一半)

backgroundCleanDisk (后臺任務(wù)過期Block +清理磁盤過期緩存)


4. ???

<1> SDWebImageManager

.h ?

-- ?SDWebImageOptions(12) + Completion/WithFinishedBlock,CacheKeyFilterBlock

-- ?delegate: -shouldDownloadImageForURL:,- transformDownloadedImage:withURL:

-- ?+sharedManager,downloadImageWithURL:~~,緩存+是否緩存~~?

.m? --? +sharedManager,+init,緩存相關(guān)(5+1),downloadImageWithURL:~~(SDCache的doneBlock( downloader的封裝 ) )

-- ?SDWebImageCombinedOperation:-setCancelBlock:,-cancel


<2> SDWebImageDecoder

.h ?-- ?decodedImageWithImage:

.m --? 不解碼動圖,alpha通道信息(alpha通道,不做解碼),顏色空間模型(其中之一),上下文中畫圖 -> 返回帶alpha的圖


<3> SDWebImagePrefetcher

.h? --? SDWebImagePrefetcherDelegate:didPrefetchURL:finishedCnt:totalCnt ,didFinishWithTotalCnt:skippedCnt:

-- PrefetcherProgress/CompletionBlock, sharedImagePrefetcher:, initWithImgManager:,prefetchURLs:,prefetchURLs:~~,cancel~

.m??

-- ?+sharedImagePrefetcher,init,最大并發(fā)數(shù)(downloader的),?startPrefetchingAtIndex:~~(self.manager downloadImageWithURL:),reportStatus(調(diào)用delegate),prefetchURLs:~~(startPrefetchingAtIndex),cancel~


5. ??????

<1> MKAnnotationView+WebCache

.h ?-- ?sd_setImageWithURL: /placeholderImage: /options: / completedBlock,sd_cancelCurrentImageLoad,sd_imageURL

.m? --? sd_imageURL(關(guān)聯(lián)對象&imageURLKey)

對外簡易接口調(diào)用內(nèi)部最復(fù)雜方法->sd_setImageWithURL:placeholderImage:options: completedBlock(取消當前圖片加載,setURL關(guān)聯(lián)對象,url有->SDWebImageManager:completed:(主線程更新UI,competedBlock) ->關(guān)聯(lián)operation,沒有->completedBlock(error)) ?

sd_cancelCurrentImageLoad(WebCacheOperation:sd_cancelCur)


<2> UIButton+WebCache? --? keyString+@(state)

.h?

--? sd_currentImageURL,sd_imageURLForState:,sd_setImageWithURL:forState:/placeholderImage:/options:/completedBlock,setBgImgWithURL:forState:/placeholderImage:/options:/completedBlock,cancelImageLoadForState:,cancelBgImageLoadForState:

.m?

懶加載-imageURLStorage(&imageURLStorageKey關(guān)聯(lián)字典) - Dict[@(state)]=url(維護不同state的url)

sd_setImageWithURL:forState:/placeholderImage:/options:/completedBlock(img:state:,取消(key+state),沒有url->移除state+主線程completedBlock,有->set,SDWebImageManager(image)+關(guān)聯(lián)operation)

setBgImgWithURL:forState:/placeholderImage:/options:/completedBlock(取消(key+state),bgImg:state:,有url->SDWebImageManager(BgImage)+關(guān)聯(lián)operation,沒有url->主線程completedBlock)

sd_set/cancel-Image/BgImage: keyString+@(state)


<3> UIImage+MultiFormat

.h ?-- ?sd_imageWithData:

.m? --? sd_imageWithData:(imageContentType: i. 動圖,ii. WebP iii. 其他+調(diào)整方向)

i. NSData+ImageContentType -- sd_contentTypeForImageData:

ii. UIImage+GIF -- sd_animatedGIFNamed, ~~GIFWithData, ~~ImageByScalingAndCroppingToSize:

iii. UIImage+WebP --?sd_imageWithWebPData:


<4> UIImageView+HighlightedWebCache

.h??

sd_setHighlightedImageWithURL:/options:/progressBlock:/completedBlock,cancelCurrentHighlightedImageLoad

.m? --? (取消,有url->SDWebImageManager(highlightedImage)+關(guān)聯(lián)operation,沒有url->主線程completedBlock))


<5> UIImageView+WebCache

.h?

--? sd_imageURL,sd_setImageWithURL:/placeholderImage:/options:/progressBlock/completedBlock,sd_setImageWithPreviousCacheImageWithURL:~~,set動畫圖片WithURLs,取消圖片/動畫圖片,顯示活動指示器/樣式

.m??

i.?sd_setImageWithURL:/placeholderImage:/options:/progressBlock/completedBlock:(取消當前,url關(guān)聯(lián)對象,延遲選項,url有->動畫+SDWebImageManager+關(guān)聯(lián)operation,沒有->completedBlock)

ii. sd_setImageWithPreviousCacheImageWithURL:~~(url->key,給key-查找內(nèi)存和磁盤(ifNeed,內(nèi)存緩存(NSCache))-返回)

iii. sd_imageURL:(關(guān)聯(lián)對象get)

iv. sd_setAnimationImagesWithURLs:

(取消,遍歷arrayOfURLs(SDWebImageManager:completed:(疊加image->animationImages)),添加operationsArray關(guān)聯(lián)對象)

&TAG_ACTIVITY_INDICATOR(UIActivityIndicatorView *)?

&TAG_ACTIVITY_SHOW(BOOL)

&TAG_ACTIVITY_STYLE(UIActivityIndicatorViewStyle)

&imageURLKey

addActivityIndicator(初始化布局+動畫)


<6> UIImage+WebCacheOperation ?-- ?關(guān)聯(lián)字典

.h ?

sd_setImageLoadOperation:forKey:,sd_cancelImageLoadOperationWithKey:

sd_removeImageLoadOperationWithKey:

.m??

operationDict(字典關(guān)聯(lián)對象,有返回,沒有set),sd_setImageLoadOperation:forKey:(取消圖片加載,set入關(guān)聯(lián)字典),sd_cancelImageLoadOperationWithKey:(關(guān)聯(lián)字典中去Key對象,是NSArray->for遍歷cancel,不是但遵循協(xié)議->調(diào)用協(xié)議cancel,remove),sd_removeImageLoadOperationWithKey:(remove出關(guān)聯(lián)字典)




UIImageView+WebCache調(diào)用過程:

sd_setImageWithURL:placeholderImage:options:progress:completed: -- 根據(jù)需要設(shè)置placeholder,通過url調(diào)用SDWebImageManager的downloadImageWithURL:options:progress:completed: -- 再通過url轉(zhuǎn)換為key,調(diào)用SDImageCache的queryDiskCacheForKey:done: -- 分別在內(nèi)存緩存和磁盤緩存(如果需要,拿出時緩存到內(nèi)存中)中查找,找到回調(diào)doneBlock(image, cacheType)。

1. 沒有圖片+默認允許下載,調(diào)用SDWebImageDownloader的downloadImageWithURL:options:progress:completed: -- 再調(diào)用addProgressCallback:completedBlock:forURL:createCallback: -- 將progressBlock和completedBlock封裝進URLCallbacks,首次創(chuàng)建會回調(diào)createCallback() —>初始化SDWebImageDownloaderOperation —> initWithRequest:options:progress:completed:cancelled: -- 設(shè)置block。然后把返回的operation加入downloadQueue。

當執(zhí)行Queue時候,會取出operation,執(zhí)行其start方法 —> [self.connection start],在下載過程中 <1> connection:didReceiveData:方法會回調(diào)progressBlock(~,~) + <2> connectionDidFinishLoading:會回調(diào)completedBlock(~~ ) + <3> cancelInternal會回調(diào)cancelBlock()?

——> <1> 在回調(diào)progressBlock(~,~)中,拿出之前存入的progressBlock(~,~)再回調(diào) <2> 在completedBlock(~~ )回調(diào)中,同樣再回調(diào)。回調(diào)后,i. 可以用delegate變換下載的圖片,變換后緩存。再回調(diào)completedBlock(~~) ?ii. 也可以不變換直接緩存,再回調(diào)completedBlock(~~)<3> cancelBlock() -> [URLCallbacks remove:url]

==>上面的<1>回調(diào)回來的progressBlock會調(diào)用用戶編寫的代碼,用于更新進度條之類的工作。上面的 i. ii. 回調(diào)的completedBlock會更新UIImageView的image。

2. 有圖片,回調(diào)?completedBlock(image, nil, cacheType, YES, url) —>同步更新UIImageView的image


學(xué)習(xí)點:

1.?

2.?


疑問:

1. 忽略 performSelector 泄露的警告

#pragma clang diagnostic push

#pragma clang diagnostic ignored"-Warc-performSelector-leaks"

idactivityIndicator =[NSClassFromString(@"SDNetworkActivityIndicator")performSelector:NSSelectorFromString(@"sharedActivityIndicator")];

#pragma clang diagnostic pop

答案:

談?wù)凮bjective-C的警告

(1) 填寫為-Wall -Wno-unused-variable即可打開“全部”警告

(2) -Wall ?+ ?-Wextra ?+ ?-Weverything

(3)

<1> Clang提供了我們自己加入警告或者暫時關(guān)閉警告的辦法。

警告類型:-W#pragma-messages, -W#warnings

<2> 比如在發(fā)布一些需要API Key之類的類庫時,可以使用這個方法來提示別的開發(fā)者別忘了輸入必要的信息。

<3> 全局關(guān)閉警告? --? Other C Flags - -Wno-... ,如 -Wextra -Wno-sign-compare

某幾個文件開啟或禁用警告? --? Compile Source - 編譯標識

某幾行關(guān)閉某個警告的話,臨時改變診斷編譯標記來抑制指定類型的警告

(4) -Wall和-Wextra

(5) Treat Warnings as Errors來開啟,或者加入-Werror標識。


NS_ENUM & NS_OPTIONS

位掩碼用NS_OPTIONS宏,語法和NS_ENUM完全相同,但這個宏提示編譯器值是如何通過位掩碼|組合在一起的。


《SDWebImage緩存圖片的機制》

How is SDWebImage better than X? - NSURLCache,NSCache,SDWebImageDecoder,AFNetworking相同

<1> 從iOS 5,NSURLCache開始處理磁盤緩存,SDWebImage比一般的NSURLRequest的優(yōu)勢在哪兒?

iOS NSURLCache對原生的HTTP響應(yīng)做內(nèi)存和磁盤緩存(從iOS 5)。對于圖片的緩存實際應(yīng)用的是NSURLCache自帶的cache機制。而NSURLCache每次都要把緩存的raw? data 再轉(zhuǎn)化為UIImage,這帶來了額外的操作,如數(shù)據(jù)解析(編碼HTTP數(shù)據(jù)),內(nèi)存copy等等。

i. 另一方面,SDWebImage緩存圖片呈現(xiàn)到內(nèi)存中,并且存儲原始壓縮(但解碼)的圖片文件到磁盤。UIImage用NSCache存儲在內(nèi)存中,因此不涉及copy,并且當app或者系統(tǒng)需要的時候,內(nèi)存會被盡快釋放。

ii. 此外,圖片解壓一般發(fā)生在主線程,你第一次在UIImageView上用UIImage時,這樣主線程會有延遲。解壓過程會被強制在后臺線程通過SDWebImageDecoder操作。

iii. 最后,SDWebImage完全忽視復(fù)雜且常誤配HTTP緩存控制協(xié)議。這極大的加速了緩存的查找。


<2>?AFNetworking提供了相似功能的UIImageView,SDWebImage還有用嗎?

當然有用,AFNetworking的優(yōu)勢是Foundation URL通過NSURLCache加載系統(tǒng)緩存,也有一個可配置的內(nèi)存緩存用于UIImageView和UIButton,默認用NSCache。緩存行為能進一步制定,通過NSURLRequest對應(yīng)的緩存策略。其他SDWebImage特性,像后臺圖片數(shù)據(jù)的解壓,AFNetworking也有。

如果你已經(jīng)用了AFNetworking且僅僅需要一個簡易的異步圖片加載分類,其內(nèi)置的UIKit extensions應(yīng)該能滿足你的需求。


移動端圖片格式調(diào)研

JPEG?是目前最常見的圖片格式,它只支持有損壓縮,其壓縮算法可以精確控制壓縮比,以圖像質(zhì)量換得存儲空間。許多移動設(shè)備的 CPU 都支持針對它的硬編碼硬解碼。

PNG?本身的設(shè)計目的是替代 GIF 格式,所以它與 GIF 有更多相似的地方。PNG 只支持無損壓縮,所以它的壓縮比是有上限的。相對于 JPEG 和 GIF 來說,它最大的優(yōu)勢在于支持完整的透明(alpha)通道。..

WebP(lossless, quality(75), method(4) - use_threads, bypass_filtering, no_fancy_upsampling) Google 的圖片格式,希望以更高的壓縮比替代 JPEG。它用 VP8 視頻幀內(nèi)編碼作為其算法基礎(chǔ),取得了不錯的壓縮效果。它支持有損無損壓縮、支持完整的透明通道、也支持多幀動畫,并且沒有版權(quán)問題,是一種非常理想的圖片格式。

GIF 通常情況下只支持256種顏色、透明通道只有1bit、文件壓縮比不高。它唯一的優(yōu)勢就是支持多幀動畫。

iOS 底層是用 ImageIO.framework 實現(xiàn)的圖片編解碼。目前 iOS 原生支持的格式有:JPEG、JPEG2000、PNG、GIF、BMP、ICO、TIFF、PICT,自 iOS8.0起,ImageIO 又加入了 APNG、SVG、RAW 格式的支持。在上層,開發(fā)者可以直接調(diào)用 ImageIO 對上面這些圖片格式進行編碼和解碼。對于動圖來說,開發(fā)者可以解碼動畫 GIF 和 APNG、可以編碼動畫 GIF。




更高效的異步圖片加載? --? CALayer

SDWebImage 在這個 Demo 里仍然會產(chǎn)生少量性能問題,并且有些地方不能滿足我的需求,所以我自己實現(xiàn)了一個性能更高圖片加載庫。在顯示簡單的單張圖片時,利用 UIView.layer.contents 就足夠了,沒必要使用 UIImageView 帶來額外的資源消耗,為此我在 CALayer 上添加了 setImageWithURL 等方法。除此之外,我還把圖片解碼等操作通過 YYDispatchQueuePool 進行管理,控制了 App 總線程數(shù)量。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,048評論 6 542
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 99,414評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事?!?“怎么了?”我有些...
    開封第一講書人閱讀 178,169評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,722評論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,465評論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,823評論 1 328
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,813評論 3 446
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 43,000評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,554評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 41,295評論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,513評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,035評論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 44,722評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,125評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,430評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,237評論 3 398
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,482評論 2 379

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