zoukankan      html  css  js  c++  java
  • SDWebImage之SDWebImageCompat

    SDWebImageCompat 是SDWebImage 的配置文件,里面利用条件编译对Apple 的各个平台进行了兼容。从源码中可以看到SDWebImage 支持当前的MAC/iOS/TV/WATCH 平台,这种适配各个平台的兼容,对框架开发意义重大。

    1.#import <TargetConditionals.h>

    导入这个头文件,能访问系统提供的配置选项。这个文件里面全部都是宏定义,主要定义了Apple 各系统平台和各CPU类型相关的宏。主要用于开发的时候针对不同的开发环境做配置使用。

    2.条件编译__OBJC_GC__

    #ifdef __OBJC_GC__
        #error SDWebImage does not support Objective-C Garbage Collection
    #endif

    Objective-C 支持内存的垃圾回收机制(Garbage collection 简称:GC)。在Mac开发是支持的,但是在iOS 开发中使用MRC/ARC,是不支持GC 的。iOS 5 之后开始支持ARC ,帮助开发者更好的管理内存,简化内存管理的难度并提高开发效率。SDWebImage 不支持GC,如果宏定义过 __OBJC_GC__,则表示是在支持GC 的开发环境,直接报错(#error)。当启动GC时,所有的retain、autorelease、release 和dealloc 方法都将被系统忽略。

    3.SD_MAC

    #if !TARGET_OS_IPHONE && !TARGET_OS_IOS && !TARGET_OS_TV && !TARGET_OS_WATCH
        #define SD_MAC 1
    #else
        #define SD_MAC 0
    #endif

    判断当前平台是不是MAC。TARGET_OS_MAC 定义在所有的平台中,比如MAC、iPhone、Watch、TV等,因此单纯的使用TARGET_OS_MAC 判断当前是不是MAC 平台是不可行的。但按照上面的判断方式,也存在一个缺点:当Apple出现新的平台时,判断条件要修改

    4.SD_UIKIT

    #if TARGET_OS_IOS || TARGET_OS_TV
        #define SD_UIKIT 1
    #else
        #define SD_UIKIT 0
    #endif

    iOS 和 tvOS 是非常相似的,UIKit在这两个平台中都存在,但是watchOS在使用UIKit时,是受限的。因此定义SD_UIKIT为真的条件是iOS 和 tvOS这两个平台。

    5.SD_IOS&&SD_TV&&SD_WATCH

    #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

    这三个宏定义用于区分iOS、TV、WATCH三个平台。

    6.平台兼容适配

    #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
        //SDWebImage不支持5.0以下的iOS版本
        #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
    • 如果SD_MAC 为真,表示在macOS 平台上开发,引入 并定义了三个宏 UIImage/UIImageView/UIView;
    • SDWebImage 不支持iOS 5.0 以下的版本;
    • SD_UIKIT 为真时引入 <UIKit/UIKit.h>;
    • SD_WATCH 为真时引入 <WatchKit/WatchKit.h>。

    7. NS_ENUM/NS_OPTIONS

    #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

    用于枚举类型。

    8.OS_OBJECT_USE_OBJC

    #if OS_OBJECT_USE_OBJC
        #undef SDDispatchQueueRelease
        #undef SDDispatchQueueSetterSementics
        #define SDDispatchQueueRelease(q)
        #define SDDispatchQueueSetterSementics strong
    #else
        #undef SDDispatchQueueRelease
        #undef SDDispatchQueueSetterSementics
        #define SDDispatchQueueRelease(q) (dispatch_release(q))
        #define SDDispatchQueueSetterSementics assign
    #endif

    OS_OBJECT_USE_OBJC宏定义是在6.0版本之后才出现的。该宏定义主要是针对GCD 的,GCD 中的对象在6.0之前是不参与ARC的,而6.0之后 在ARC下使用GCD不用关心释放问题。  对于最低sdk 版本 >= iOS 6.0来说,GCD 对象已经纳入了ARC 的管理范围,我们就不需要再手工调用 dispatch_release 了;否则的话,在sdk < 6.0的时候;即使开启了ARC ,这个宏OS_OBJECT_USE_OBJC 也是没有的,也就是说这个时候,GCD对象还必须得自己管理。

    如果开发的项目最低目标低于 iOS 6.0 or Mac OS X 10.8,应该自己管理GCD对象;使用(dispatch_retain ,dispatch_release),ARC 并不会去管理它们。

    如果开发的项目最低目标是 iOS 6.0 or Mac OS X 10.8 或者更高的,ARC 已经能够管理GCD 对象了,这时候GCD 对象就如同普通的OC 对象一样,不应该使用dispatch_retain , ordispatch_release 。

    9.API

    //给定一张图片,通过参数key调整scale属性,返回对应分辨率下面的图片
    extern UIImage *SDScaledImageForKey(NSString *key, UIImage *image);
    
    typedef void(^SDWebImageNoParamsBlock)();
    
    extern NSString *const SDWebImageErrorDomain;
    
    static int64_t kAsyncTestTimeout = 5;

    10.dispatch_main_async_safe

    #ifndef dispatch_main_async_safe
    #define dispatch_main_async_safe(block)
        if (strcmp(dispatch_queue_get_label(DISPATCH_CURRENT_QUEUE_LABEL), dispatch_queue_get_label(dispatch_get_main_queue())) == 0) {
            block();
        } else {
            dispatch_async(dispatch_get_main_queue(), block);
        }
    #endif

    在主线程中安全的执行任务Block。

    在项目中,如果当前线程已经是主线程,那么在调用dispatch_async(dispatch_get_main_queue(), block)有可能会出现crash。因此做了一个判断:当前线程是主线程,直接调用Block;如果不是,那么调用dispatch_async(dispatch_get_main_queue(), block)。

    11.全局方法SDScaledImageForKey

    /**
     给定一张图片,通过参数key调整scale属性,返回对应分辨率下面的图片
    
     @param key 图片名称
     @param image 资源图片
     @return 处理以后的图片
     */
    inline UIImage *SDScaledImageForKey(NSString * _Nullable key, UIImage * _Nullable image) {
        //异常处理
        if (!image) {
            return nil;
        }
        
    #if SD_MAC
        return image;
    #elif SD_UIKIT || SD_WATCH
        //如果是动态图片,比如GIF图片,则迭代处理
        if ((image.images).count > 0) {
            NSMutableArray<UIImage *> *scaledImages = [NSMutableArray array];
            //迭代处理每一张图片
            for (UIImage *tempImage in image.images) {
                [scaledImages addObject:SDScaledImageForKey(key, tempImage)];
            }
            //把处理结束的图片再合成一张动态图片
            return [UIImage animatedImageWithImages:scaledImages duration:image.duration];
        }
        else {
    #if SD_WATCH
            if ([[WKInterfaceDevice currentDevice] respondsToSelector:@selector(screenScale)]) {
    #elif SD_UIKIT
            if ([[UIScreen mainScreen] respondsToSelector:@selector(scale)]) {
    #endif
                CGFloat scale = 1;
                // “@2x.png”的长度为7,所以此处添加了这个判断,很巧妙
                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
    }
  • 相关阅读:
    WPF中的句柄
    WPF中的焦点问题
    Vue项目(一):VSCode环境开发Vue程序以及其中遇到的问题
    C#实现三种方式的模拟按键
    c++温故之结构体写法
    WPF搜索框
    vue框架学习
    Git连接失败问题解决方案
    单击双击冲突解决 小程序
    uniapp 微信小程序 wx.createAnimation 实现向上滚动弹幕
  • 原文地址:https://www.cnblogs.com/LeeGof/p/6912566.html
Copyright © 2011-2022 走看看