UIImage+GIF 是UIImage 类的一个GIF 分类,在之前的版本里面这个分类是用了处理GIF 动态图片的但是会有内存暴增的bug。在当前 '4.0.0-beta2' 的版本里GIF 动态图片处理放在了UIImage+MultiFormat  这个分类里面,而当前这个GIF 的分类的功能只是将动态图片作为静态图片来处理,如果是静态图片的NSData 数据则转化为静态UIImage 直接返回,如果是动态图片的NSData 数据,则把图像的第1帧图像转换化为静态UIImage 返回。

  首先看UIImage+GIF.h 文件:

 1 @interface UIImage (GIF)
 2
 3 /**
 4  *  Compatibility method - creates an animated UIImage from an NSData, it will only contain the 1st frame image
 5  */
 6 + (UIImage *)sd_animatedGIFWithData:(NSData *)data;
 7
 8 /**
 9  *  Checks if an UIImage instance is a GIF. Will use the `images` array
10  */
11 - (BOOL)isGIF;
12
13 @end

  定义了一个实例方法和一个类方法:

1 + (UIImage *)sd_animatedGIFWithData:(NSData *)data;

  兼容的方法创建一个动画UIImage 从一个NSData,它仅仅只包含第一帧图像。

  判断一个UIImage 实例是否是GIF 图片:

1 - (BOOL)isGIF;

1 - (BOOL)isGIF {
2     return (self.images != nil);
3 }

  检查一个UIImage 的实例是否是GIF,将使用“images” 数组判断。

  UIImage+GIF.m 文件:

  主要研究上面类方法的实现。

  学习研究之前先做一些拓展:

  size_t 类型:

  size_t 类型定义在cstddef 头文件中,该文件是C标准库的头文件stddef.h 的C++ 版。它是一个与机器相关的unsigned类型,其大小足以保证存储内存中对象的大小。

  例如:bitset 的size 操作返回bitset对象中二进制位中的个数,返回值类型是size_t。

例如:在用下标访问元素时,vector使用vector:size_type 作为下标类型,而数组下标的正确类型则是size_t。vector 使用的下标实际也是size_t,源码是: typedef size_t size_type。
来源:

  size_t 是标准C库中定义的,应为unsigned int,在64位系统中为 long unsigned int。

  使用:

一个基本的无符号整数的 C/C ++ 类型,它是sizeof 操作符返回的结果类型,该类型的大小可选择。因此,它可以存储在理论上是可能的任何类型的数组的最大大小。换句话说,一个指针可以被安全地放进size_t 类型(一个例外是类的函数指针,但是这是一个特殊的情况)。
size_t 类型通常用于循环、数组索引、大小的存储和地址运算。 虽然size_t 可以存储一个指针,它的目的是更好地使用另一个unsinged 整数类型uintptr_t 形式。在某些情况下,使用size_t 类型是更为有效,比习惯性使用无符号类型的程序会更安全。
size_t是在基于无符号整数memsize 类型的 C/C++ 的标准库中定义的。C语言中,此类型位于头文件stddef.h 中,而在C++ 中,则位于cstddef.h 中。

  实现方式:

  在C++ 中,设计 size_t 就是为了适应多个平台的。size_t 的引入增强了程序在不同平台上的可移植性。

  size_t 是针对系统定制的一种数据类型,一般是整型,因为 C/C++ 标准只定义最低的位数,而不是必需的固定位数。而且在内存里,对数的高位对齐存储还是低位对齐存储各系统都不一样。为了提高代码的可移植性,就有必要定义这样的数据类型。一般这种类型都会定义到它具体占几位内存等。当然,有些是编译器或系统已经给定义好的。

  经测试发现,在32位系统中size_t是4字节的,而在64位系统中,size_t 是8字节的,这样利用该类型可以增强程序的可移植性。

  详细解释:

size_t 在C语言中就有了。
它是一种“整型”类型,里面保存的是一个整数,就像int, long那样。这种整数用来记录一个大小(size),size_t 的全称应该是size type,就是说“一种用来记录大小的数据类型”。
用sizeof(xxx) 操作可获取 xxx 占用的内存空间字节数,sizeof 返回的必定是无符号整形,在标准c中通过 typedef 将返回值类型定义为size_t。strlen 获取字符数组实际使用的字节数,不包含数组结尾符’\0’,返回类型size_t。
若用printf 输出size_t 类型时,C99 中定义格式符 %zd,若编译器不支持可以尝试%u 或%lu 。
因为size_t类型的数据其实是保存了一个整数,所以它也可以做加减乘除,也可以转化为int并赋值给int类型的变量。
类似的还有wchar_t, ptrdiff_t。wchar_t就是wide char type,“一种用来记录一个宽字符的数据类型”。ptrdiff_t就是pointer difference type,“一种用来记录两个指针之间的距离的数据类型”。
通常,size_t 和ptrdiff_t 都是用typedef 来实现的。你可能在某个头文件里面找到类似的语句:
typedef unsigned int size_t; 而wchar_t则稍有不同。在一些旧的编译器中,wchar_t也可能是用typedef来实现,但是新的标准中wchar_t已经是 C/C++ 语言的关键字,wchar_t 类型的地位已经和char, int的地位等同了。
在标准C/C++的语法中,只有int float char bool等基本的数据类型,至于size_t 或size_type 都是以后的编程人员为了方便记忆所定义的一些便于理解的由基本数据类型的变体类型。
例如:typedef int size_t; 定义了size_t为整型。

  在编译的过程中size_t类型的a 值会被编译他的补码。所以在使用size_t 类型数据的过程中尤其要注意,特别是在逻辑表达式中使用到该类型,稍不注意可能带来很严重的后果。 
  注:正数的补码:与原码相同;负数的补码:符号位为1,其余位为该数绝对值的原码按位取反,然后整个数加1。

参考链接:http://blog.csdn.net/JIEJINQUANIL/article/details/50981834

http://jeremybai.github.io/blog/2014/09/10/size-t

http://baike.baidu.com/link?url=WhKafqypjk2GpAfTxbeWLNEQIqW3bjODmV5faNTtZUcPPCn1Y7MDOa05UR4DOstvaVcbGeOXqUcKCRJ6eIz4ba

http://blog.csdn.net/zhanghaotian2011/article/details/7974891

http://www.cnblogs.com/kaituorensheng/p/3239446.html

http://blog.csdn.net/bigloomy/article/details/6563870

  下面看 + (UIImage *)sd_animatedGIFWithData:(NSData *)data; 方法实现:

 1 + (UIImage *)sd_animatedGIFWithData:(NSData *)data {
 2     if (!data) {
 3         return nil;
 4     }
 5
 6     CGImageSourceRef source = CGImageSourceCreateWithData((__bridge CFDataRef)data, NULL);
 7
 8     size_t count = CGImageSourceGetCount(source);
 9
10     UIImage *staticImage;
11
12     if (count <= 1) {
13         staticImage = [[UIImage alloc] initWithData:data];
14     } else {
15         // we will only retrieve the 1st frame. the full GIF support is available via the FLAnimatedImageView category.
16         // this here is only code to allow drawing animated images as static ones
17 #if SD_WATCH
18         CGFloat scale = 1;
19         scale = [WKInterfaceDevice currentDevice].screenScale;
20 #elif SD_UIKIT
21         CGFloat scale = 1;
22         scale = [UIScreen mainScreen].scale;
23 #endif
24
25         CGImageRef CGImage = CGImageSourceCreateImageAtIndex(source, 0, NULL);
26 #if SD_UIKIT || SD_WATCH
27         UIImage *frameImage = [UIImage imageWithCGImage:CGImage scale:scale orientation:UIImageOrientationUp];
28         staticImage = [UIImage animatedImageWithImages:@[frameImage] duration:0.0f];
29 #elif SD_MAC
30         staticImage = [[UIImage alloc] initWithCGImage:CGImage size:NSZeroSize];
31 #endif
32         CGImageRelease(CGImage);
33     }
34
35     CFRelease(source);
36
37     return staticImage;
38 }

  这里主要使用了 ImageIO 框架下的 <ImageIO/CGImageSource.h>,并在 UIImage+GIF.m 文件开始通过 #import <ImageIO/ImageIO.h>,引入ImageIO 框架。

  1.判断传入的data 如果是nil 则直接返回nil。

  2.使用CGImageSource.h 的:CGImageSourceCreateWithData((__bridge CFDataRef)data, NULL),创建一个CGImageSourceRef 对象source。

1 /* Create an image source reading from `data'.  The `options' dictionary
2  * may be used to request additional creation options; see the list of keys
3  * above for more information. */
4
5 IMAGEIO_EXTERN CGImageSourceRef __nullable CGImageSourceCreateWithData(CFDataRef __nonnull data, CFDictionaryRef __nullable options) IMAGEIO_AVAILABLE_STARTING(__MAC_10_4, __IPHONE_4_0);

  3.使用CGImageSource.h 的:CGImageSourceGetCount(source),获得source 里面的图片数量count。

1 /* Return the number of images (not including thumbnails) in the image
2  * source `isrc'. */
3
4 IMAGEIO_EXTERN size_t CGImageSourceGetCount(CGImageSourceRef __nonnull isrc)  IMAGEIO_AVAILABLE_STARTING(__MAC_10_4, __IPHONE_4_0);

  4.创建一个UIImage 实例staticImage。(从名字里面能大概猜出创建该实例的用意)

  5.如果count 小于等于1,即表示该data 数据是一个静态图片的NSData 数据,则把data 转化为UIImage 并赋值给staticImage。

  6.如果count 大于1,即表示该data 数据是一个动态图片的NSData 数据。如果当前是WATCH 平台开发通过:

1         CGFloat scale = 1;
2         scale = [WKInterfaceDevice currentDevice].screenScale;

获取当前设备的screenScale,如果是iOS/TV 平台开发(包含UIKit 框架)通过:

1         CGFloat scale = 1;
2         scale = [UIScreen mainScreen].scale;

获得当前屏幕的scale,并赋值给float 类型的scale 变量,用于控制返回的动态图片的第一帧图像的大小。

  7.使用CGImageSource.h 的:CGImageSourceCreateImageAtIndex(source, 0, NULL),获得source 里面index 为0 时的CGImageRef 实例CGImage。

1 /* Return the image at `index' in the image source `isrc'.  The index is
2  * zero-based. The `options' dictionary may be used to request additional
3  * creation options; see the list of keys above for more information. */
4
5 IMAGEIO_EXTERN CGImageRef __nullable CGImageSourceCreateImageAtIndex(CGImageSourceRef __nonnull isrc, size_t index, CFDictionaryRef __nullable options)  IMAGEIO_AVAILABLE_STARTING(__MAC_10_4, __IPHONE_4_0);

  8.如果是iOS/TV/WATCH 平台开发,根据上面获取的CGImage 和scale 做参数,使用:

1 + (UIImage *)imageWithCGImage:(CGImageRef)cgImage scale:(CGFloat)scale orientation:(UIImageOrientation)orientation NS_AVAILABLE_IOS(4_0);

创建一个UIImage 实例frameImage。

  9.把frameImage 放在一个NSArray 里面作参数,使用:

1 + (nullable UIImage *)animatedImageWithImages:(NSArray<UIImage *> *)images duration:(NSTimeInterval)duration NS_AVAILABLE_IOS(5_0);

创建一个images 为一张图片,duration 为0.0f的动态图片并赋值给staticImage。如果是MAC 平台开发,依然CGImage 作参数,使用:

1 [[UIImage alloc] initWithCGImage:CGImage size:NSZeroSize];

创建一个UIImage 实例赋值给staticImage。

  10.使用CGImage.h 的CGImageRelease(CGImage) 释放CGImage。

1 /* Equivalent to `CFRelease(image)'. */
2
3 CG_EXTERN void CGImageRelease(CGImageRef cg_nullable image)
4     CG_AVAILABLE_STARTING(__MAC_10_0, __IPHONE_2_0);

  11.使用CFBase.h 的CFRelease(source)  释放source。

1 CF_EXPORT
2 void CFRelease(CFTypeRef cf);

  12.返回staticImage。

END

参考链接:http://www.jianshu.com/p/d3e9e3d0a778

转载于:https://www.cnblogs.com/chmhml/p/6797045.html

SDWebImage源码阅读(三)UIImage+GIF相关推荐

  1. 24 UsageEnvironment使用环境抽象基类——Live555源码阅读(三)UsageEnvironment

    24 UsageEnvironment使用环境抽象基类--Live555源码阅读(三)UsageEnvironment 24 UsageEnvironment使用环境抽象基类--Live555源码阅读 ...

  2. mybatis源码阅读(三):mybatis初始化(下)mapper解析

    转载自 mybatis源码阅读(三):mybatis初始化(下)mapper解析 MyBatis 的真正强大在于它的映射语句,也是它的魔力所在.由于它的异常强大,映射器的 XML 文件就显得相对简单. ...

  3. SDWebImage源码阅读(九)SDWebImageDownloader

    这篇学习 SDWebImageDownloader 这个类. 首先依然是看 SDWebImageDownloader.h: SDWebImageDownloaderOptions 1 typedef ...

  4. Struts2源码阅读(三)_DispatcherConfigurationProvider

    首先强调一下struts2的线程程安全,在Struts2中大量采用ThreadLocal线程局部变量的方法来保证线程的安全,像Dispatcher等都是通过ThreadLocal来保存变量值,使得每个 ...

  5. SpringMVC源码阅读(三)

    先理一下Bean的初始化路线 org.springframework.beans.factory.support.AbstractBeanDefinitionReader public int loa ...

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

    该文章阅读的SDWebImage的版本为4.3.3. 由于这几个分类都是UIImage的分类,并且内容相对较少,就写在一篇文章中. 1.UIImage+ForceDecode 这个分类为UIImage ...

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

    该文章阅读的SDWebImage的版本为4.3.3. 这个类提供了四个方法,这四个方法可分为两类,一类是动图处理,一类是图像方向处理. 1.私有函数 先来看一下这个类里的两个函数 /**这个函数是计算 ...

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

    该文章阅读的SDWebImage的版本为4.3.3. 根据SDWebImage作者的描述,这个类是用来帮助创建动图的. 1.接口文件 属性 /**当前帧的图像*/ @property (nonatom ...

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

    该文章阅读的SDWebImage的版本为4.3.3. 这个分类提供了为UIButton设置网络图像的快捷方法. 1.公共方法 1.1.设置image的方法 /**获取当前图像链接地址*/ - (nul ...

最新文章

  1. 知乎 高级操作系统_知乎高赞:Linux!为何他一人就写出这么强的系统,中国却做不出来?...
  2. malloc 和alloc及calloc的区别
  3. 什么是 SAP C/4HANA Foundation
  4. promehteus 监控超时_05 . Prometheus监控Nginx
  5. Visual Studio 清单(manifest)导致的问题
  6. STM32的2.02固件库提供的启动文件详解 stm32f10x_vector.s
  7. python3文档字符串_python3基础:字符串、文本文件
  8. ArcGIS 道路线数据处理与拓扑操作
  9. LC.234.Palindrome Linked List
  10. java多线程编程--模拟龟兔赛跑过程
  11. Abaqus有限元分析软件介绍
  12. 网页页面缩小放大的快捷键
  13. 大司、小司、外包公司
  14. python求单词长度_python 统计单词平均长度,统计a出现的次数
  15. 新显卡出世,谈谈与深度学习有关的显卡架构和相关技术
  16. 一.正则表达式转换为有限状态自动机:正则表达式转NFA
  17. 30系显卡安装tensorflow-gpu1.15
  18. 抢先看! Lumion 10 正式发布之核心功能预览
  19. 基于STM32F4的智能门锁系统
  20. 服务器怎么使用无线网卡,无线上网卡怎么用

热门文章

  1. 日志服务接入方式之Unity 3D篇
  2. LINUX_egrep及扩展正则表达式
  3. sql2005/sql2000 向表中循环插入100万条记录
  4. 【联盟】三星大容量MLC FLASH 换代信息(小心现在自己计划的产品哦)
  5. 大山深处,有一所希望学校
  6. 经验之谈——送给年轻的职场人
  7. Fully decentralized NFT system towards Metaverse: Next generation Seatlab business model
  8. 为什么一定要好好睡觉?
  9. 剑桥大学eap入学测试准备!!!救命稻草
  10. 虚拟打印机开发日志(一):使用x64 WIN7编译环境编译的完整步骤