0x0背景
原本是放到自己博客的席楚,不怎么用了凭需,把文章同步過(guò)來(lái)染乌,原文地址[iOS/OC]SDWebImage和LKImage對(duì)比
LKImageKit是騰訊開(kāi)源的一個(gè)高性能圖片加載框架瘫辩,雖然第一時(shí)間下載了源碼伏嗜,但是只是簡(jiǎn)單的看了框架,沒(méi)有細(xì)致的研讀源碼伐厌。最近空閑下來(lái)承绸,學(xué)習(xí)了一下LKImageKit源碼,其中有很多巧妙的實(shí)現(xiàn)挣轨。本文將通過(guò)1張圖片的加載流程军熏,對(duì)比兩個(gè)圖片框架。
0x1正文
LKImageKit和SDWebImage分別選用了兩種不同的圖片加載方案卷扮。LKImageKit的圖片加載是提供了一個(gè)LKImageView荡澎,加載圖片需要使用指定的容器。SDWebImage是寫(xiě)了一個(gè)Category画饥,加載圖片可以使用系統(tǒng)的UIImageView或其子類(lèi)衔瓮。流程上。
1.入口
發(fā)起一個(gè)圖片加載抖甘,LKImageKit是在layoutSubviews時(shí)热鞍,發(fā)起1次圖片加載,SDWebImage提供了1個(gè)主動(dòng)發(fā)起圖片加載請(qǐng)求的接口sd_setImageWithUrl
LKImageKit發(fā)起圖片加載:
// 上層調(diào)用
imageView.URL = [NSURL urlWithString:@"https://xxx.png"];
imageView.request.synchronized = YES;
// 底層加載
- (void)layoutSubviews {
[super layoutSubviews];
[self layoutAndLoad];
}
SDWebImage發(fā)起圖片加載
// 上層調(diào)用
[imageView sd_setImageWithURL:[NSURL URLWithString:@""]];
// 之后開(kāi)始下載流程
兩個(gè)圖片庫(kù)都提供了加載回調(diào)衔彻,不同的是薇宠,LKImageKit提供的是delegate的方法,SDWebImage提供的是callback
LKImageKit
@protocol LKImageViewDelegate <NSObject>
@optional
- (void)LKImageViewImageLoading:(LKImageView *)imageView request:(LKImageRequest *)request;
- (void)LKImageViewImageDidLoad:(LKImageView *)imageView request:(LKImageRequest *)request;
@end
SDWebImage
typedef void(^SDWebImageCompletionBlock)(UIImage * _Nullable image, NSError * _Nullable error, SDImageCacheType cacheType, NSURL * _Nullable imageURL);
2.下載
LKImageKit進(jìn)行圖片下載會(huì)統(tǒng)一由LKImageManger進(jìn)行管理艰额,LKImageKit提供的請(qǐng)求合并的優(yōu)化就是通過(guò)LKImageManager進(jìn)行的澄港。請(qǐng)求會(huì)通過(guò)blockOperation放到1個(gè)operationQueue中進(jìn)行多個(gè)加載請(qǐng)求的隊(duì)列管理。
資源加載則由LKImageLoader進(jìn)行柄沮,由單例LKImageLoaderManager進(jìn)行管理回梧。網(wǎng)絡(luò)下載是LKImageNetworkFileLoader進(jìn)行废岂,使用了NSURLSession,本地圖片加載通過(guò)LKImageLocalFileLoader進(jìn)行狱意。
[requestLV2.loader dataWithRequest:requestLV2
callback:^(LKImageRequest *requestLV2, NSData *data, float progress, NSError *error) {
[self loadDataRequestFinished:requestLV2 data:data progress:progress error:error];
}];
SDWebImage進(jìn)行圖片下載由SDWebImageManager進(jìn)行管理湖苞。類(lèi)似的,在SDWebImage 5.0版本開(kāi)始详囤,也使用SDWebImageLoader進(jìn)行加載财骨,使用SDWebImageLoadersManager進(jìn)行管理。網(wǎng)絡(luò)下載使用SDWebImageDownloader進(jìn)行藏姐。使用NSOperation進(jìn)行下載管理隆箩。
[self downloadImageWithURL:url options:downloaderOptions context:context progress:progressBlock completed:completedBlock];
對(duì)比可知,LKImageKit在下載前做了很多優(yōu)化羔杨,下載流程的管理更加細(xì)膩捌臊。SDWebImage的下載過(guò)程由于歷史原因,雖然在5.0上大刀闊斧的改造了很多東西兜材,但是整體流程會(huì)顯得更加笨重一些娃属。
3.圖片解碼
LKImageKit和SDWebImage的圖片解碼大同小異,以L(fǎng)KImageKit為例:
// 由LKImageDecoderManager進(jìn)行解碼器的管理
UIImage *image = [decoder imageFromData:data request:request error:&decode_error];
// 普通靜圖
result = [UIImage imageWithData:data scale:[UIScreen mainScreen].scale];
// 1幀的動(dòng)圖
UIImage *image = [UIImage imageWithCGImage:imageRef scale:[UIScreen mainScreen].scale orientation:orientation];
// 動(dòng)圖
UIImage *image = [UIImage animatedImageWithImages:images duration:INFINITY];
4.圖片解壓縮
圖片解壓縮是將解碼后的image解出bitmap护姆,從而避免系統(tǒng)主線(xiàn)程解壓縮導(dǎo)致的主線(xiàn)程卡頓的問(wèn)題矾端。這里兩個(gè)庫(kù)也都是大同小異。以L(fǎng)KImageKit為例:
CGContextRef context = CGBitmapContextCreate(NULL, clipSize.width, clipSize.height, 8, 0, colorspace, bitmapInfo);
CGContextDrawImage(context, imageRect, input.CGImage);
CGImageRef cgimage = CGBitmapContextCreateImage(context);
UIImage *image = [UIImage imageWithCGImage:cgimage scale:screenScale orientation:input.imageOrientation];
不同的是卵皂,LKImageKit因?yàn)槭怯玫闹付ǖ娜萜鬟M(jìn)行全鏈路的圖片加載秩铆,所以可以通過(guò)打通全鏈路,在解壓縮時(shí)灯变,提前獲取加載的容器大小殴玛,然后根據(jù)容器的大小進(jìn)行按需解bitmap,從而節(jié)約內(nèi)存添祸。
開(kāi)源SDWebImage并沒(méi)有這個(gè)優(yōu)化滚粟。我自己在SDWebImage上實(shí)現(xiàn)了一套類(lèi)似的方案,需要從接口調(diào)用到解bitmap全鏈路打通刃泌,透?jìng)魅萜鞔笮“葱杞獯a凡壤,以及對(duì)帶alpha通道的webp圖片等的異常case處理。略有不同的是耙替,LKImageKit使用了image的scale屬性亚侠,SDWebImage的scale默認(rèn)1,需要做額外的pt->px的轉(zhuǎn)換俗扇。后續(xù)有機(jī)會(huì)會(huì)把代碼提到開(kāi)源倉(cāng)庫(kù)硝烂。
0x2總結(jié)
兩種圖片方案有各自的業(yè)務(wù)場(chǎng)景和出發(fā)點(diǎn),各有好處铜幽。
LKImageKit方案對(duì)圖片的管理能力更強(qiáng)滞谢,圖片加載的流程對(duì)于框架更加透明串稀;SDWebImage方案更加靈活,尤其在5.0后狮杨,各種擴(kuò)展性都非常好厨诸,LKImageKit的下載、解碼管理有明顯的借鑒SDWebImage的痕跡禾酱。另外,對(duì)于圖片的加載流程绘趋,LKImageKit更加細(xì)膩颤陶,比如請(qǐng)求合并,按需解bitmap陷遮。
同時(shí)滓走,從商業(yè)角度看,微信帽馋、QQ等大型App搅方,是需要對(duì)圖片加載全鏈路進(jìn)行埋點(diǎn)監(jiān)控的,這種強(qiáng)勢(shì)掌控加載細(xì)節(jié)的LKImageKit方案绽族,處理其這樣的需求更加便利姨涡。猜想騰訊內(nèi)部的LKImageKit版本應(yīng)該還有埋點(diǎn)監(jiān)控、網(wǎng)絡(luò)接管等更多模塊的適配接口吧慢,開(kāi)源的只是刪減了相關(guān)依賴(lài)的外部版本涛漂。