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 cache = [[self class] defaultImageCache];
    if (!cache) {
        cache = [SDImageCache sharedImageCache];
    }
    id loader = [[self class] defaultImageLoader];
    if (!loader) {
        loader = [SDWebImageDownloader sharedDownloader];
    }
    return [self initWithCache:cache loader:loader];
}

- (nonnull instancetype)initWithCache:(nonnull id)cache loader:(nonnull id)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;
}

判断二进制文件类型原理

你可能感兴趣的:(SDWebImage源码分析)