SDWebImage是什么
SDWebImage是一个提供了高效的图片异步加载、图片缓存和图片处理等功能的一个第三方开源框架。
SDWebImage做了什么,怎么做?
接口设计
用UIKit相关类的Category封装图片加载的接口。
图片下载
图片下载管理器SDImageLoadersManager+NSOperationQueue+自定义NSOperation并重写start、finish、cancel等方法用于管理图片加载队列。
图片缓存
缓存图片,分内缓存和磁盘缓存,同时配合着多种缓存策略,以供开发者根据具体业务需求选择使用。
- 内存缓存使用NSCache+NSMapTable&dispatch_semaphore_t配合使用
- 磁盘缓存使用NSFileManager+GCD串行队列管理图片文件的读写。
图片的其他处理。
- 图片编解码,分生成位图直接解码和渐进式解码两种。
- 动态图片展示。
- 图片转换等相关操作。
- 图片格式判断
SDWebImage为什么要这么做?
接口为什么用Category
Category封装接口方便调用。
图片下载队列管理
NSOperationQueue+自定义NSOperation并重写start、finish等方法用于管理图片加载队列,为了start和finish在一个线程里执行,方便管理,这样外部就只关心队列的本身的本身。
图片缓存机制
分内缓存和磁盘缓存。配合各种缓存策略实现。
- 内存缓存,NSCache+NSMapTable配合使用
NSCache是真正的缓存,NSMapTable只是弱引用,当收到内存警告时移除的是NSCache的引用,此时如果图片对象在页面在被引用,内存还是会存在的,依然可以通过NSMapTable来访问。 - 磁盘缓存,磁盘缓存使用NSFileManager管理图片文件 + GCD串行队列保证安全。
配合着多种缓存策略,开发者可以根据业务需求自行选择,同时根据自身app性能做做一些自定义的优化。内存缓存大小和过期时间都可以自定义,收到内存警告清理掉NSCache,只保留NSMapTable的弱引用。
内存优化
- 针对UITableView内存优化,设置加载低优先级,这样下载队列和解码队列优先级会变低,在ScrollView滚动减速时加载。避免了在页面发生交互时加载图片,减轻CPU压力。
- 大图优化,对于大图可以选择不缓存图片,同时可以在解码时设置图片的目标尺寸,减少内存占用。同时动图解码时使用渐进式解码,避免同时解码造成内存暴增。
图片的其他处理。
- 两种解码:
解码有两种方式,通过异步队列调用管理解码任务。实现原理NSOperationQueue&addOperationWithBlock+maxCount = 1?为了可以取消任务?downloader->coderQueue->Block(解码操作)
解码1-直接生成位图解码:downloader->coderQueue->CGImageRef-> CGBitmapContextCreate(CGContextRef)->CGContextDrawImage->CGBitmapContextCreateImage
1、创建一张位图的上下文Context=CGBitmapContextCreate
2、绘制图片到这个CGContextDrawImage(Content)
3、通过上下文Content生成图片newImageRef=CGBitmapContextCreateImage(Content)
核心代码如下:
CGBitmapInfo bitmapInfo = kCGBitmapByteOrder32Host;
bitmapInfo |= hasAlpha ? kCGImageAlphaPremultipliedFirst : kCGImageAlphaNoneSkipFirst;
CGContextRef context = CGBitmapContextCreate(NULL, newWidth, newHeight, 8, 0, [self colorSpaceGetDeviceRGB], bitmapInfo);
if (!context) {
return NULL;
}
// Apply transform
CGAffineTransform transform = SDCGContextTransformFromOrientation(orientation, CGSizeMake(newWidth, newHeight));
CGContextConcatCTM(context, transform);
CGContextDrawImage(context, CGRectMake(0, 0, width, height), cgImage); // The rect is bounding box of CGImage, don't swap width & height
CGImageRef newImageRef = CGBitmapContextCreateImage(context);
CGContextRelease(context);
解码2-渐进式解码:
CGImageSourceCreateIncremental->CGImageSourceUpdateData->CGImageSourceCreateImageAtIndex
1、CGImageSourceCreateIncremental创建一个空的CGImageSourceRef
2、图片数据更新之后调用CGImageSourceUpdateData将图片数据ImageData更新到CGImageSourceRef中
3、CGImageSourceCreateImageAtIndex生成CGImageRef
- 动图展示。通过CADisplayLink利用屏幕刷新频率和Runloop的空闲时间显示动图,提高性能。
- 圆角。UIGraphicsImageRenderer(imageWithActions)->UIBezierPath(贝塞尔曲线)->UIGraphicsImageRendererContext。UIGraphicsImageRendererContext可以复用渲染上下文,提高效率。
- 图片格式判断。通过图片数据的第一个字节判断或者通过CGImageSourceRef获取图片格式
网友评论