iOS开发奇技淫巧

[iOS/OC]SDWebImage和LKImage对比

2018-09-25  本文已影响0人  斯瑞德

0x0背景

原本是放到自己博客的,不怎么用了,把文章同步过来,原文地址[iOS/OC]SDWebImage和LKImage对比

LKImageKit是腾讯开源的一个高性能图片加载框架,虽然第一时间下载了源码,但是只是简单的看了框架,没有细致的研读源码。最近空闲下来,学习了一下LKImageKit源码,其中有很多巧妙的实现。本文将通过1张图片的加载流程,对比两个图片框架。

0x1正文

LKImageKit和SDWebImage分别选用了两种不同的图片加载方案。LKImageKit的图片加载是提供了一个LKImageView,加载图片需要使用指定的容器。SDWebImage是写了一个Category,加载图片可以使用系统的UIImageView或其子类。流程上。

1.入口

发起一个图片加载,LKImageKit是在layoutSubviews时,发起1次图片加载,SDWebImage提供了1个主动发起图片加载请求的接口sd_setImageWithUrl

LKImageKit发起图片加载:

// 上层调用
imageView.URL = [NSURL urlWithString:@"https://xxx.png"];
imageView.request.synchronized = YES;

// 底层加载
- (void)layoutSubviews {
    [super layoutSubviews];
    [self layoutAndLoad];
}

SDWebImage发起图片加载

// 上层调用
[imageView sd_setImageWithURL:[NSURL URLWithString:@""]];

// 之后开始下载流程

两个图片库都提供了加载回调,不同的是,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进行图片下载会统一由LKImageManger进行管理,LKImageKit提供的请求合并的优化就是通过LKImageManager进行的。请求会通过blockOperation放到1个operationQueue中进行多个加载请求的队列管理。

资源加载则由LKImageLoader进行,由单例LKImageLoaderManager进行管理。网络下载是LKImageNetworkFileLoader进行,使用了NSURLSession,本地图片加载通过LKImageLocalFileLoader进行。

[requestLV2.loader dataWithRequest:requestLV2
                          callback:^(LKImageRequest *requestLV2, NSData *data, float progress, NSError *error) {
                              [self loadDataRequestFinished:requestLV2 data:data progress:progress error:error];
                          }];

SDWebImage进行图片下载由SDWebImageManager进行管理。类似的,在SDWebImage 5.0版本开始,也使用SDWebImageLoader进行加载,使用SDWebImageLoadersManager进行管理。网络下载使用SDWebImageDownloader进行。使用NSOperation进行下载管理。

[self downloadImageWithURL:url options:downloaderOptions context:context progress:progressBlock completed:completedBlock];

对比可知,LKImageKit在下载前做了很多优化,下载流程的管理更加细腻。SDWebImage的下载过程由于历史原因,虽然在5.0上大刀阔斧的改造了很多东西,但是整体流程会显得更加笨重一些。

3.图片解码

LKImageKit和SDWebImage的图片解码大同小异,以LKImageKit为例:

// 由LKImageDecoderManager进行解码器的管理
UIImage *image = [decoder imageFromData:data request:request error:&decode_error];

// 普通静图
result = [UIImage imageWithData:data scale:[UIScreen mainScreen].scale];

// 1帧的动图
UIImage *image = [UIImage imageWithCGImage:imageRef scale:[UIScreen mainScreen].scale orientation:orientation];

// 动图
UIImage *image = [UIImage animatedImageWithImages:images duration:INFINITY];

4.图片解压缩

图片解压缩是将解码后的image解出bitmap,从而避免系统主线程解压缩导致的主线程卡顿的问题。这里两个库也都是大同小异。以LKImageKit为例:

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因为是用的指定的容器进行全链路的图片加载,所以可以通过打通全链路,在解压缩时,提前获取加载的容器大小,然后根据容器的大小进行按需解bitmap,从而节约内存。

开源SDWebImage并没有这个优化。我自己在SDWebImage上实现了一套类似的方案,需要从接口调用到解bitmap全链路打通,透传容器大小按需解码,以及对带alpha通道的webp图片等的异常case处理。略有不同的是,LKImageKit使用了image的scale属性,SDWebImage的scale默认1,需要做额外的pt->px的转换。后续有机会会把代码提到开源仓库。

0x2总结

两种图片方案有各自的业务场景和出发点,各有好处。

LKImageKit方案对图片的管理能力更强,图片加载的流程对于框架更加透明;SDWebImage方案更加灵活,尤其在5.0后,各种扩展性都非常好,LKImageKit的下载、解码管理有明显的借鉴SDWebImage的痕迹。另外,对于图片的加载流程,LKImageKit更加细腻,比如请求合并,按需解bitmap。

同时,从商业角度看,微信、QQ等大型App,是需要对图片加载全链路进行埋点监控的,这种强势掌控加载细节的LKImageKit方案,处理其这样的需求更加便利。猜想腾讯内部的LKImageKit版本应该还有埋点监控、网络接管等更多模块的适配接口,开源的只是删减了相关依赖的外部版本。

上一篇下一篇

猜你喜欢

热点阅读