博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
SDWebImage学习
阅读量:7231 次
发布时间:2019-06-29

本文共 7445 字,大约阅读时间需要 24 分钟。

SDWebImage简介

SDWebImage是iOS开发中主流的图像加载库,它帮我们处理内存缓存磁盘缓存与及图像加载的一系列操作。使用起来方便快捷,让我们更好的专注于业务逻辑的开发。

组织结构

SDWebImage框架组成如下:

SDWebImage类图.png

功能快速一览图:

SDWebImage架构.png

SDWebImageCompat 做机型适配的。

SDWebImageManager管理缓存和下载的一个类。
SDImageCache处理缓存和内存的类。
SDWebImageDownloader异步下载器专用和优化图像加载。
SDWebImagePrefetcher图片的预加载。

源码解析

SDImageCache

SDImageCache是继承自NSObject的。做了cache的一些基本配置和cache的管理。

如cache的大小,cache的有效期,添加cache,删除cache等。

cache的类型如下:

typedef NS_ENUM(NSInteger, SDImageCacheType) {    /**     * The image wasn't available the SDWebImage caches, but was downloaded from the web.(不缓存,从web加载)     */    SDImageCacheTypeNone,    /**     * The image was obtained from the disk cache.(磁盘缓存)     */    SDImageCacheTypeDisk,    /**     * The image was obtained from the memory cache.(内存缓存)     */    SDImageCacheTypeMemory};

内部的AutoPurgeCache是继承自NSCache的,主要用途是在收到系统的UIApplicationDidReceiveMemoryWarningNotification通知时,清理内存缓存。

此外,SDWebCache的内存缓存也是使用的NSCache.

设置缓存的核心方法如下:

- (void)storeImage:(UIImage *)image recalculateFromImage:(BOOL)recalculate imageData:(NSData *)imageData forKey:(NSString *)key toDisk:(BOOL)toDisk {    if (!image || !key) {        return;    }    // if memory cache is enabled    if (self.shouldCacheImagesInMemory) {        NSUInteger cost = SDCacheCostForImage(image);        [self.memCache setObject:image forKey:key cost:cost];    }    if (toDisk) {        dispatch_async(self.ioQueue, ^{            NSData *data = imageData;            if (image && (recalculate || !data)) {#if TARGET_OS_IPHONE                // We need to determine if the image is a PNG or a JPEG                // PNGs are easier to detect because they have a unique signature (http://www.w3.org/TR/PNG-Structure.html)                // The first eight bytes of a PNG file always contain the following (decimal) values:                // 137 80 78 71 13 10 26 10                // If the imageData is nil (i.e. if trying to save a UIImage directly or the image was transformed on download)                // and the image has an alpha channel, we will consider it PNG to avoid losing the transparency                int alphaInfo = CGImageGetAlphaInfo(image.CGImage);                BOOL hasAlpha = !(alphaInfo == kCGImageAlphaNone ||                                  alphaInfo == kCGImageAlphaNoneSkipFirst ||                                  alphaInfo == kCGImageAlphaNoneSkipLast);                BOOL imageIsPng = hasAlpha;                // But if we have an image data, we will look at the preffix                if ([imageData length] >= [kPNGSignatureData length]) {                    imageIsPng = ImageDataHasPNGPreffix(imageData);                }                if (imageIsPng) {                    data = UIImagePNGRepresentation(image);                }                else {                    data = UIImageJPEGRepresentation(image, (CGFloat)1.0);                }#else                data = [NSBitmapImageRep representationOfImageRepsInArray:image.representations usingType: NSJPEGFileType properties:nil];#endif            }            [self storeImageDataToDisk:data forKey:key];        });    }}

从代码可以看出,先设置的内存缓存,再设置的磁盘缓存。

- (void)removeImageForKey:(NSString *)key fromDisk:(BOOL)fromDisk withCompletion:(SDWebImageNoParamsBlock)completion {        if (key == nil) {        return;    }    if (self.shouldCacheImagesInMemory) {        [self.memCache removeObjectForKey:key];    }    if (fromDisk) {        dispatch_async(self.ioQueue, ^{            [_fileManager removeItemAtPath:[self defaultCachePathForKey:key] error:nil];                        if (completion) {                dispatch_async(dispatch_get_main_queue(), ^{                    completion();                });            }        });    } else if (completion){        completion();    }    }

删除缓存的时候也是先删除内存缓存,在删除磁盘缓存。

UIImageView+WebCache

通过UIImageView集成SDWebImage异步下载和缓存远程图像。

下载图片的核心方法如下:

- (void)sd_setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder options:(SDWebImageOptions)options progress:(SDWebImageDownloaderProgressBlock)progressBlock completed:(SDWebImageCompletionBlock)completedBlock {    [self sd_cancelCurrentImageLoad];    objc_setAssociatedObject(self, &imageURLKey, url, OBJC_ASSOCIATION_RETAIN_NONATOMIC);    if (!(options & SDWebImageDelayPlaceholder)) {        dispatch_main_async_safe(^{ //保证是在主线程中设置图片            self.image = placeholder;        });    }        if (url) {        // check if activityView is enabled or not        if ([self showActivityIndicatorView]) {            [self addActivityIndicator];        }        __weak __typeof(self)wself = self;        id 
operation = [SDWebImageManager.sharedManager downloadImageWithURL:url options:options progress:progressBlock completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL) { [wself removeActivityIndicator]; if (!wself) return; dispatch_main_sync_safe(^{ if (!wself) return; if (image && (options & SDWebImageAvoidAutoSetImage) && completedBlock) { completedBlock(image, error, cacheType, url); return; } else if (image) { wself.image = image; [wself setNeedsLayout]; } else { if ((options & SDWebImageDelayPlaceholder)) { wself.image = placeholder; [wself setNeedsLayout]; } } if (completedBlock && finished) { completedBlock(image, error, cacheType, url); } }); }]; [self sd_setImageLoadOperation:operation forKey:@"UIImageViewImageLoad"]; } else { dispatch_main_async_safe(^{ [self removeActivityIndicator]; if (completedBlock) { NSError *error = [NSError errorWithDomain:SDWebImageErrorDomain code:-1 userInfo:@{NSLocalizedDescriptionKey : @"Trying to load a nil url"}]; completedBlock(nil, error, SDImageCacheTypeNone, url); } }); }}

从代码可以看出,代码使用时runtime为分类添加属性,设置placeholder一定是在住线程中进行的,图片真正的下载操作,使用的是SDWebImageOperation

图片加载的时序图:

图片加载时序图

而且这里有两个值得我们学习的宏定义:

#define dispatch_main_sync_safe(block)\    if ([NSThread isMainThread]) {\        block();\    } else {\        dispatch_sync(dispatch_get_main_queue(), block);\    }

保证同步线程是在主线程执行的。

#define dispatch_main_async_safe(block)\    if ([NSThread isMainThread]) {\        block();\    } else {\        dispatch_async(dispatch_get_main_queue(), block);\    }

保证异步线程是在主线程执行的。

SDWebImageManager

SDWebImageManager是整个框架的一个核心类,它把SDImageCacheSDWebImageDownloader结合在一起,同时管理图片的下载和缓存操作。

SDWebImageOptions这个options,提供了我们下载图片时的很多可选操作。

示例如下:

/**     * By default, when a URL fail to be downloaded, the URL is blacklisted so the library won't keep trying.     * 默认情况下,当一个 URL 下载失败,该URL被列入黑名单,将不会继续尝试下载     * This flag disable this blacklisting.     * 此标志取消黑名单     */    SDWebImageRetryFailed = 1 << 0,    /**     * By default, image downloads are started during UI interactions, this flags disable this feature,     * 默认情况下,在 UI 交互时也会启动图像下载,此标记取消这一功能     * leading to delayed download on UIScrollView deceleration for instance.     * 会延迟下载,UIScrollView停止滚动之后再继续下载     * 下载事件监听的运行循环模式是 NSDefaultRunLoopMode     */    SDWebImageLowPriority = 1 << 1,    /**     * This flag disables on-disk caching     * 禁用磁盘缓存     */    SDWebImageCacheMemoryOnly = 1 << 2,

注:

转载地址:http://vgpfm.baihongyu.com/

你可能感兴趣的文章
Android学习笔记进阶18 之画图并保存图片到本地
查看>>
安装wxWidgets遭遇的两大关卡
查看>>
MapReduce实战(六)共同粉丝
查看>>
Java 实现单链表反序
查看>>
移植alsa-lib遇到的问题
查看>>
镜像的缓存特性 - 每天5分钟玩转 Docker 容器技术(14)
查看>>
[Node.js]多进程
查看>>
面试归来,感觉无望,下次再战
查看>>
C#之值类型和引用类型
查看>>
项目经理的五种权利
查看>>
病态矩阵与条件数
查看>>
Java IntelliJ IDEA 不能显示项目里的文件结构
查看>>
HDU 5325 Crazy Bobo(思路+dfs 记忆化)
查看>>
.NET平台常用的框架整理
查看>>
使用EmbeddedValueResolverAware读取配置文件内容
查看>>
打印从1到最大的n位数
查看>>
drawnet.py绘制网络结构
查看>>
Javascript中apply、call、bind
查看>>
电脑显示U盘,可是读取不了
查看>>
Linux时间子系统之八:动态时钟框架(CONFIG_NO_HZ、tickless)
查看>>