SDWebImage源码分析

前言:
因为SDWebImage这个框架真的太常用了,所以具体的使用方法就不在这里做细说,下文也只会提到简单的方法用, SDWebImage的github文档中有说明使用SDWebImage的github传送门;

官方结构图

SDWebImageClassDiagram.png

1.SDWebImage的一些类

1.1 UIView(WebCache)

我们可以看到源码中提供了如下类别:
UIImageView(WebCache)/SDAnimatedImageView(WebCache)/UIButton(WebCache)
这些类别声明了可直接调用的加载图片的方法,而最后这些暴露的方法最后会统一调用UIView(WebCache)里面的方法:sd_internalSetImageWithURL:...

案例代码:
/**加载gif图片*/
-(void)method2{
    NSURL *gifURL = [NSURL URLWithString:url2];
    /**
     加载图片的方法
     @param URL 图片链接
     @param placeholderImage 展位图
     @param options 加载策略,是一个枚举
     @param progress 加载进度回调
     @param completed 加载完成回调
     */
/*
options:
SDWebImageRetryFailed -> 下载失败后,会重新下载
SDWebImageLowPriority -> 低优先级,当有视图滚动的时候先暂停加载
SDWebImageProgressiveLoad -> 显示进度,图片一点一点显示;
SDWebImageRefreshCached ->  每一次都会重新加载图片,
SDWebImageContinueInBackground->应用在后台的时候还可以加载图片
SDWebImageHandleCookies->是否处理cookies
SDWebImageHighPriority->高优先级
SDWebImageDelayPlaceholder->imageholder在加载完图片的时候才出现,没什么意义这个设置
这个枚举还有很多别的值情况,详细请到源码中查询
*/
    [self.sdImageView sd_setImageWithURL:gifURL placeholderImage:nil options:SDWebImageRefreshCached progress:^(NSInteger receivedSize, NSInteger expectedSize, NSURL *targetURL) {
        //获得下载进度
        //receivedSize 收到的数据大小
        //expectedSize 期待收到的数据大小->下载目标的大小
        //targetURL 下载的url
        NSLog(@"url:%@",targetURL);
    } completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, NSURL *imageURL) {
       //加载结束回调
        //image 图片本身
        //error 如果发生错误则返回error,否则error=nil
        //cacheType 加载图片的模式
        /*
        SDImageCacheTypeNone, 0 表示图像不再内存中,是从网络获取的
        SDImageCacheTypeDisk, 1  图片在沙盒中获取
        SDImageCacheTypeMemory, 2 图片是从运行的内存从中获取的
        SDImageCacheTypeAll, 所有的情况 (在删除SD缓存的时候也用到这个枚举)
        */
        NSLog(@"image.size:%@",NSStringFromCGSize(image.size));
    }];
}

1.2 SDImageCache

SDWebImage 这个框架中,提供了一个SDImageCache协议,和一个SDImageCache
SDImageCache协议-> 提供了关于图片的缓存处理方法:

SDImageCache.png

SDImageCache类-> 在其初始化的时候,添加了三个监听:

#if SD_UIKIT
// Subscribe to app events
 [[NSNotificationCenter defaultCenter] addObserver:self
                                          selector:@selector(applicationWillTerminate:)
                                              name:UIApplicationWillTerminateNotification
                                            object:nil];


[[NSNotificationCenter defaultCenter] addObserver:self
                                   selector:@selector(applicationDidEnterBackground:)
                                      name:UIApplicationDidEnterBackgroundNotification
                                     object:nil];
#endif
#if SD_MAC

        [[NSNotificationCenter defaultCenter] addObserver:self
                                                 selector:@selector(applicationWillTerminate:)
                                                 name:NSApplicationWillTerminateNotification
                                                   object:nil];
#endif

1.3 SDWebImageManager

SDWebImageManager->框架的管理者,继承于NSObject,它是一个单例,在其初始化方法的内部直接为其属性初始化:

SDWebImageManager暴露的方法.png

+ (nonnull instancetype)sharedManager {
    static dispatch_once_t once;
    static id instance;
    dispatch_once(&once, ^{
        instance = [self new];
    });
    return instance;
}

- (nonnull instancetype)init {
    id<SDImageCache> cache = [[self class] defaultImageCache];
    if (!cache) {
        cache = [SDImageCache sharedImageCache];
    }
    id<SDImageLoader> loader = [[self class] defaultImageLoader];
    if (!loader) {
        loader = [SDWebImageDownloader sharedDownloader];
    }
    return [self initWithCache:cache loader:loader];
}

- (nonnull instancetype)initWithCache:(nonnull id<SDImageCache>)cache loader:(nonnull id<SDImageLoader>)loader {
    if ((self = [super init])) {
        _imageCache = cache;
        _imageLoader = loader;
        _failedURLs = [NSMutableSet new];
        _failedURLsLock = dispatch_semaphore_create(1);
        _runningOperations = [NSMutableSet new];
        _runningOperationsLock = dispatch_semaphore_create(1);
    }
    return self;
}

  • SDWebImageDownloader下载管理类类,但是其最终任务不是用这个类来执行,而是派发到 :SDWebImageDownloaderOperation这个类来执行的.它继承于NSOperation;

SDWebImageDownloader的实例对象可以通过其属性defaultDownloaderConfig进行配置设置,因为defaultDownloaderConfig是一个只读属性,所以只能通过调用以下方法进行设置:

- (nonnull instancetype)initWithConfig:(nullable SDWebImageDownloaderConfig *)config;

//defaultDownloaderConfig 提供的属性有:
//maxConcurrentDownloads //最大下载数 默认6
//downloadTimeout //下载超时 默认15秒
//minimumProgressInterval //进度回调的精度 0.0-1.0 越小越精确
//还有别的属性,不会常用到,不一一罗列

2.使用什么下载方式?

SDWebImageDownloaderOperation.m文件中使用了NSURLSession的下载方式进行图片下载,2016年的时候是用的NSURLConnection的方式来进行下载的,后来改版了

3.加载完成后的处理

3.1存放路径

Library/Caches/com.hackemist.SDImageCache/default

3.2命名规则

下载链接进行MD5加密后拼接上文件后缀就是加载的文件命名

3.3如何判断下载的图片类型 JPG?/PNG?/GIF?

NSData+ImageContentType这个类提供了一个判断类型的方法,改方法根据二进制文件的第一个字节判断二进制文件的类型;

+ (SDImageFormat)sd_imageFormatForImageData:(nullable NSData *)data;

/*SDImageFormat是一个枚举类型:
typedef NSInteger SDImageFormat NS_TYPED_EXTENSIBLE_ENUM;
static const SDImageFormat SDImageFormatUndefined = -1;
static const SDImageFormat SDImageFormatJPEG      = 0;
static const SDImageFormat SDImageFormatPNG       = 1;
static const SDImageFormat SDImageFormatGIF       = 2;
static const SDImageFormat SDImageFormatTIFF      = 3;
static const SDImageFormat SDImageFormatWebP      = 4;
static const SDImageFormat SDImageFormatHEIC      = 5;
static const SDImageFormat SDImageFormatHEIF      = 6;
*/

+ (SDImageFormat)sd_imageFormatForImageData:(nullable NSData *)data {
    if (!data) {
        return SDImageFormatUndefined;
    }
    
    // File signatures table: http://www.garykessler.net/library/file_sigs.html
    uint8_t c;
    [data getBytes:&c length:1];
    switch (c) {
        case 0xFF:
            return SDImageFormatJPEG;
        case 0x89:
            return SDImageFormatPNG;
        case 0x47:
            return SDImageFormatGIF;
        case 0x49:
        case 0x4D:
            return SDImageFormatTIFF;
        case 0x52: {
            if (data.length >= 12) {
                //RIFF....WEBP
                NSString *testString = [[NSString alloc] initWithData:[data subdataWithRange:NSMakeRange(0, 12)] encoding:NSASCIIStringEncoding];
                if ([testString hasPrefix:@"RIFF"] && [testString hasSuffix:@"WEBP"]) {
                    return SDImageFormatWebP;
                }
            }
            break;
        }
        case 0x00: {
            if (data.length >= 12) {
                //....ftypheic ....ftypheix ....ftyphevc ....ftyphevx
                NSString *testString = [[NSString alloc] initWithData:[data subdataWithRange:NSMakeRange(4, 8)] encoding:NSASCIIStringEncoding];
                if ([testString isEqualToString:@"ftypheic"]
                    || [testString isEqualToString:@"ftypheix"]
                    || [testString isEqualToString:@"ftyphevc"]
                    || [testString isEqualToString:@"ftyphevx"]) {
                    return SDImageFormatHEIC;
                }
                //....ftypmif1 ....ftypmsf1
                if ([testString isEqualToString:@"ftypmif1"] || [testString isEqualToString:@"ftypmsf1"]) {
                    return SDImageFormatHEIF;
                }
            }
            break;
        }
    }
    return SDImageFormatUndefined;
}

判断二进制文件类型原理

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,734评论 6 505
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,931评论 3 394
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,133评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,532评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,585评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,462评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,262评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,153评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,587评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,792评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,919评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,635评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,237评论 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,855评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,983评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,048评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,864评论 2 354