源码阅读:SDWebImage(二)——SDWebImageCompat

该文章阅读的SDWebImage的版本为4.3.3。

这个类是一个配置类,类似于一个配置文件,也可以说是一个兼容类,用于兼容不同平台。


先看这个类导入的头文件#import <TargetConditionals.h>。这个头文件的内容是苹果提供的配置条件,它会自动配置编译器所要编译的代码将要使用的微处理器指令集、运行系统以及运行时环境。


#ifdef __OBJC_GC__
    #error SDWebImage does not support Objective-C Garbage Collection
#endif
复制代码
  • 首先来看__OBJC_GC__这个宏,这个宏的意思是,是否支持Objective-C的垃圾回收机制
  • 然后#error定义了一个错误,当Xcode在编译时遇到这个预编译指令就会停止编译,错误的内容就是SDWebImage不支持Objective-C的垃圾回收机制
  • 所以,这段代码的意思就很明显了:SDWebImage不支持Objective-C的垃圾回收机制

#if !TARGET_OS_IPHONE && !TARGET_OS_IOS && !TARGET_OS_TV && !TARGET_OS_WATCH
    #define SD_MAC 1
#else
    #define SD_MAC 0
#endif
复制代码

这段代码定义了一个宏SD_MAC,这样做的目的根据SDWebImage的作者的描述是,苹果提供TARGET_OS_MAC这个宏有点儿迷、不靠谱,所以就自定义了一个:如果不是TARGET_OS_IPHONETARGET_OS_IOSTARGET_OS_TVTARGET_OS_WATCH就是MAC平台。否则就不是。


#if TARGET_OS_IOS || TARGET_OS_TV
    #define SD_UIKIT 1
#else
    #define SD_UIKIT 0
#endif
复制代码

这段代码定义了一个宏SD_UIKIT,来判断是否有UIKit,因为UIKit存在于iOStvOS两个平台。所以,只要是这两个平台中的任何一个就有UIKit


#if TARGET_OS_IOS
    #define SD_IOS 1
#else
    #define SD_IOS 0
#endif
复制代码
#if TARGET_OS_TV
    #define SD_TV 1
#else
    #define SD_TV 0
#endif
复制代码
#if TARGET_OS_WATCH
    #define SD_WATCH 1
#else
    #define SD_WATCH 0
#endif
复制代码

至于为什么要定义这三个,我个人的考虑可能是以后苹果的定义可能会变,这样写的话,就不在每个用到这个宏的地方去做修改,这需要在这一个文件的这一个地方修改就可以了。


#if SD_MAC
    #import <AppKit/AppKit.h>
    #ifndef UIImage
        #define UIImage NSImage
    #endif
    #ifndef UIImageView
        #define UIImageView NSImageView
    #endif
    #ifndef UIView
        #define UIView NSView
    #endif
#else
    #if __IPHONE_OS_VERSION_MIN_REQUIRED != 20000 && __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_5_0
        #error SDWebImage doesn't support Deployment Target version < 5.0
    #endif

    #if SD_UIKIT
        #import <UIKit/UIKit.h>
    #endif
    #if SD_WATCH
        #import <WatchKit/WatchKit.h>
    #endif
#endif
复制代码
  • 如果在MAC平台上,会做一些转换:把NSImage转换成UIImage、把NSImageView转换成UIImageView、把NSView转换成UIView,这样做的好处是,不用因为平台的不同再做判断或者再多写一份代码了。

  • 如果不是MAC平台,先定义了一个错误:SDWebImage不支持iOS5.0以下的版本,至于__IPHONE_OS_VERSION_MIN_REQUIRED != 20000这个判断我没太看明白,查了好多资料感觉合理的解释是:好像如果用模拟器跑的话__IPHONE_OS_VERSION_MIN_REQUIRED的值会是20000,但是我用模拟器跑了一下并不是这样的,可能是Xcode更新了的缘故?接着,根据是否是watchOS导入不同的头文件。


#ifndef NS_ENUM
#define NS_ENUM(_type, _name) enum _name : _type _name; enum _name : _type
#endif

#ifndef NS_OPTIONS
#define NS_OPTIONS(_type, _name) enum _name : _type _name; enum _name : _type
#endif
复制代码

因为NS_ENUMNS_OPTIONS都是在iOS 6 / OS X Mountain Lion才开始有,但是根据上面那段可知,SDWebImage兼容到iOS5,所以这算是重新定义兼容iOS5


FOUNDATION_EXPORT UIImage *SDScaledImageForKey(NSString *key, UIImage *image);
复制代码

这是定义了一个公共函数用来缩放图片。直接来看实现

inline UIImage *SDScaledImageForKey(NSString * _Nullable key, UIImage * _Nullable image) {
    // 如果没有传入图片就不继续向下执行了
    if (!image) {
        return nil;
    }
    
    // 如果是MAC平台也不向下执行了
#if SD_MAC
    return image;
#elif SD_UIKIT || SD_WATCH
    if ((image.images).count > 0) {
        // 如果是动图,就遍历出所有的图片后递归调用该函数进行缩放,然后返回
        NSMutableArray<UIImage *> *scaledImages = [NSMutableArray array];

        for (UIImage *tempImage in image.images) {
            [scaledImages addObject:SDScaledImageForKey(key, tempImage)];
        }
        
        UIImage *animatedImage = [UIImage animatedImageWithImages:scaledImages duration:image.duration];
        if (animatedImage) {
            animatedImage.sd_imageLoopCount = image.sd_imageLoopCount;
        }
        return animatedImage;
    } else {
#if SD_WATCH
        if ([[WKInterfaceDevice currentDevice] respondsToSelector:@selector(screenScale)]) {
#elif SD_UIKIT
        if ([[UIScreen mainScreen] respondsToSelector:@selector(scale)]) {
#endif
            // 根据传入的key中所包含的@2x和@3x来缩放图片至对应的比例后返回
            CGFloat scale = 1;
            if (key.length >= 8) {
                NSRange range = [key rangeOfString:@"@2x."];
                if (range.location != NSNotFound) {
                    scale = 2.0;
                }
                
                range = [key rangeOfString:@"@3x."];
                if (range.location != NSNotFound) {
                    scale = 3.0;
                }
            }

            UIImage *scaledImage = [[UIImage alloc] initWithCGImage:image.CGImage scale:scale orientation:image.imageOrientation];
            image = scaledImage;
        }
        return image;
    }
#endif
}
复制代码

对于这个函数,我的理解是根据图片地址链接中是否包含@2x和@3x信息,如果有,就把图片缩放到指定比例。


typedef void(^SDWebImageNoParamsBlock)(void);
复制代码

这就是定义了一个名字为SDWebImageNoParamsBlock,参数为空,返回值为空的代码块,方便使用。


FOUNDATION_EXPORT NSString *const SDWebImageErrorDomain;
复制代码
NSString *const SDWebImageErrorDomain = @"SDWebImageErrorDomain";
复制代码

定义了一个静态字符串用于作为错误信息的key


#ifndef dispatch_queue_async_safe
#define dispatch_queue_async_safe(queue, block)\
    if (strcmp(dispatch_queue_get_label(DISPATCH_CURRENT_QUEUE_LABEL), dispatch_queue_get_label(queue)) == 0) {\
        block();\
    } else {\
        dispatch_async(queue, block);\
    }
#endif

#ifndef dispatch_main_async_safe
#define dispatch_main_async_safe(block) dispatch_queue_async_safe(dispatch_get_main_queue(), block)
#endif
复制代码

这个宏就是使想要执行的代码块block,在主线程主队列执行。


#if !__has_feature(objc_arc)
    #error SDWebImage is ARC only. Either turn on ARC for the project or use -fobjc-arc flag
#endif
复制代码
#if !OS_OBJECT_USE_OBJC
    #error SDWebImage need ARC for dispatch object
#endif
复制代码

这两个错误的意思都是说:SDWebImage只支持ARC

好了,到这儿,这个类我们就看完了。之所以先看这个类,因为基本每个类都会调用这个类,所以看完了这个类,以后再看其他类就会方便很多。

源码阅读系列:SDWebImage

源码阅读:SDWebImage(一)——从使用入手

源码阅读:SDWebImage(二)——SDWebImageCompat

源码阅读:SDWebImage(三)——NSData+ImageContentType

源码阅读:SDWebImage(四)——SDWebImageCoder

源码阅读:SDWebImage(五)——SDWebImageFrame

源码阅读:SDWebImage(六)——SDWebImageCoderHelper

源码阅读:SDWebImage(七)——SDWebImageImageIOCoder

源码阅读:SDWebImage(八)——SDWebImageGIFCoder

源码阅读:SDWebImage(九)——SDWebImageCodersManager

源码阅读:SDWebImage(十)——SDImageCacheConfig

源码阅读:SDWebImage(十一)——SDImageCache

源码阅读:SDWebImage(十二)——SDWebImageDownloaderOperation

源码阅读:SDWebImage(十三)——SDWebImageDownloader

源码阅读:SDWebImage(十四)——SDWebImageManager

源码阅读:SDWebImage(十五)——SDWebImagePrefetcher

源码阅读:SDWebImage(十六)——SDWebImageTransition

源码阅读:SDWebImage(十七)——UIView+WebCacheOperation

源码阅读:SDWebImage(十八)——UIView+WebCache

源码阅读:SDWebImage(十九)——UIImage+ForceDecode/UIImage+GIF/UIImage+MultiFormat

源码阅读:SDWebImage(二十)——UIButton+WebCache

源码阅读:SDWebImage(二十一)——UIImageView+WebCache/UIImageView+HighlightedWebCache

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值