iOS:关于加载GIF图片的思考

iOS:关于加载GIF图片的思考

iOS:关于加载GIF图片的思考(2023-03-27更新)

前言GIF原理加载方式UIImageViewSDWebImageQExtensionWKWebViewYYImageQMUI

简单的优化总结素材学习资料

前言

最近在项目中需要加入一个动画效果,设计师在导出Lottie动画后发现并不能达到效果,就想使用gif图片来实现。 但是将gif图片放入项目中运行时发现了一些问题,所以在这里整理一下有关加载gif图片的问题! 以下观点都是作者个人进行了不严谨的简单测试得出的结论,如有错误请多多包涵,欢迎讨论!

GIF原理

GIF的全称是Graphics Interchange Format,可译为图形交换格式,用于以超文本标志语言(Hypertext Markup Language)方式显示索引彩色图像,在因特网和其他在线服务系统上得到广泛应用。GIF是一种公用的图像文件格式标准,版权归Compu Serve公司所有。 详细去读GIF百度百科即可,我们不必深究。简单的将GIF理解为循环播放的幻灯片(个人见解)。

加载方式

UIImageViewSDWebImageQExtensionWKWebViewYYImageQMUI 就以下6种方式进行讨论,根据实际需求情况选择显示方案,我个人还是推荐使用YYimage,具体如下:

UIImageView

系统提供的UIimageView是支持多张图片的播放的,类似于播放幻灯片,但是这样就需要先将*.gif*文件先进行抽帧为单独的帧图片,再进行播放,很麻烦!但是实现确实很简单的,如果只是少数几张图片的切换的话,还是可以选择的。

#pragma mark - eg

UIImageView *gifImageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 400, 300)];

gifImageView.animationImages = @[]; // 存放每一帧的UIImage的数组

gifImageView.animationDuration = 5; // 执行一次完整动画所需的时长

gifImageView.animationRepeatCount = 1;// 动画重复次数

[gifImageView startAnimating];

[self.view addSubView:gifImageView];

#pragma mark - UIImageView Api

@property (nonatomic, getter=isHighlighted) BOOL highlighted API_AVAILABLE(ios(3.0)); // default is NO

// these allow a set of images to be animated. the array may contain multiple copies of the same

@property (nullable, nonatomic, copy) NSArray *animationImages; // The array must contain UIImages. Setting hides the single image. default is nil

@property (nullable, nonatomic, copy) NSArray *highlightedAnimationImages API_AVAILABLE(ios(3.0)); // The array must contain UIImages. Setting hides the single image. default is nil

@property (nonatomic) NSTimeInterval animationDuration; // for one cycle of images. default is number of images * 1/30th of a second (i.e. 30 fps)

@property (nonatomic) NSInteger animationRepeatCount; // 0 means infinite (default is 0)

// When tintColor is non-nil, any template images set on the image view will be colorized with that color.

// The tintColor is inherited through the superview hierarchy. See UIView for more information.

@property (null_resettable, nonatomic, strong) UIColor *tintColor API_AVAILABLE(ios(7.0));

- (void)startAnimating;

- (void)stopAnimating;

@property(nonatomic, readonly, getter=isAnimating) BOOL animating;

NSURL *fileUrl = [[NSBundle mainBundle] URLForResource:@"<#gifName#>" withExtension:@"gif"]; //加载GIF图片

CGImageSourceRef gifSource = CGImageSourceCreateWithURL((CFURLRef) fileUrl, NULL); //将GIF图片转换成对应的图片源

size_t frameCout = CGImageSourceGetCount(gifSource); //获取其中图片源个数,即由多少帧图片组成

NSMutableArray *frames = [[NSMutableArray alloc] init]; //定义数组存储拆分出来的图片

for (size_t i = 0; i < frameCout; i++) {

CGImageRef imageRef = CGImageSourceCreateImageAtIndex(gifSource, i, NULL); //从GIF图片中取出源图片

UIImage *imageName = [UIImage imageWithCGImage:imageRef]; //将图片源转换成UIimageView能使用的图片源

[frames addObject:imageName]; //将图片加入数组中

CGImageRelease(imageRef);

}

UIImageView *gifImageView = [[UIImageView alloc] initWithFrame:CGRectMake(<#x#>, <#y#>, <#w#>, <#h#>)];

gifImageView.animationImages = frames; //将图片数组加入UIImageView动画数组中

gifImageView.animationDuration = 0.15; //每次动画时长

[gifImageView startAnimating]; //开启动画,此处没有调用播放次数接口,UIImageView默认播放次数为无限次,故这里不做处理

[self.view addSubview:gifImageView];

SDWebImage

SDWebImage可以说是加载图片的常用三方库了,尝试着使用了一下,但是却发现了很严重的内存占用问题。加载一次GIF在高帧数的情况下内存直接暴涨了近200M有的100多M,这肯定是不推荐使用了!

#import

#pragma mark - eg

// 注意

UIImageView *gifImageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 400, 300)];

NSString *filePath = [[NSBundle bundleWithPath:[[NSBundle mainBundle] bundlePath]] pathForResource:@"test" ofType:@"gif"];

NSData *imageData = [NSData dataWithContentsOfFile:filePath];

gifImageView.image = [UIImage sd_imageWithGIFData:imageData];

[self.view addSubView:gifImageView];

QExtension

QExtension是一个对很多类进行了拓展的三方,提供了很多方法,但是只有较少人使用,同样在使用时发生了和SDWebImage一样的内存问题,所以并不推荐使用!

#import

#pragma mark - eg

// 注意

UIImageView *gifImageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 400, 300)];

NSString *filePath = [[NSBundle bundleWithPath:[[NSBundle mainBundle] bundlePath]] pathForResource:@"test" ofType:@"gif"];

NSData *imageData = [NSData dataWithContentsOfFile:filePath];

gifImageView.image = [UIImage q_gifImageWithData:imageData];

[self.view addSubView:gifImageView];

WKWebView

系统的WKWebView也是可以对GIF的数据进行展示的,而且在内存方面就友好很多,不会暴涨,我在测试时 涨了7M。使用起来也很简单,只是少量的需求,且不想引入更多三方的话,可以考虑使用!

#import

#pragma mark - eg

WKWebView *gifView = [[WKWebView alloc] initWithFrame:CGRectMake(0, 0, 400, 300)];

NSString *filePath = [[NSBundle bundleWithPath:[[NSBundle mainBundle] bundlePath]] pathForResource:@"test" ofType:@"gif"];

NSData *imageData = [NSData dataWithContentsOfFile:filePath];

[gifView loadData:imageData MIMEType:@"image/gif" characterEncodingName:@"" baseURL:[NSURL URLWithString:@""]];

[self.view addSubView:gifView];

YYImage

YYImage也可以说是很出名的一个三方了,它对UIimageView和UIImage都进行了很好的扩展,在播放GIF图片上的优化也是做的很好!由于是对UIimageView的扩展,它具有所有UIimageView的特性,兼容性很好!我在测试时内存涨了6M。

#import

#pragma mark - eg

UIImageView *gifImageView = [[YYAnimatedImageView alloc] initWithFrame:CGRectMake(0, 0, 400, 300)];

UIImage *img = [YYImage imageNamed:@"test.gif"];

gifImageView.image = img;

[self.view addSubView:gifImageView];

GIF图片直接放在Bundle里就可以了!

QMUI

腾讯开发的QMUI库也提供了加载GIF的方法,经过想学习发现内部实现是这样的:

+ (UIImage *)qmui_animatedImageWithData:(NSData *)data scale:(CGFloat)scale {

// http://www.jianshu.com/p/767af9c690a3

// https://github.com/rs/SDWebImage

if (!data) {

return nil;

}

CGImageSourceRef source = CGImageSourceCreateWithData((__bridge CFDataRef)data, NULL);

size_t count = CGImageSourceGetCount(source);

UIImage *animatedImage = nil;

scale = scale == 0 ? ScreenScale : scale;

if (count <= 1) {

animatedImage = [[UIImage alloc] initWithData:data scale:scale];

} else {

NSMutableArray *images = [[NSMutableArray alloc] init];

NSTimeInterval duration = 0.0f;

for (size_t i = 0; i < count; i++) {

CGImageRef image = CGImageSourceCreateImageAtIndex(source, i, NULL);

duration += [self qmui_frameDurationAtIndex:i source:source];

UIImage *frameImage = [UIImage imageWithCGImage:image scale:scale orientation:UIImageOrientationUp];

[images addObject:frameImage];

CGImageRelease(image);

}

if (!duration) {

duration = (1.0f / 10.0f) * count;

}

animatedImage = [UIImage animatedImageWithImages:images duration:duration];

}

CFRelease(source);

return animatedImage;

}

其本质还是使用NSData的方法加载UIImage。

简单的优化

在2023年3月25日,进行Timer Profiler检查时,发现YYImage显示GIF,即使进入后台依旧在占用线程。 在使用QMUI进行同一张GIF加载对比后发现 QMUI对于加载时间和进入后台后的表现优于YYImage。

#import

#pragma mark - eg

UIImageView *gifImageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 400, 400)];

gifImageView.image = [UIImage qmui_animatedImageNamed:@"test.gif"];

[self.view addSubView:gifImageView];

但是,内存方面,YYImage却大大的优于QMUI 对于进入后台后,YYAnimatedImageView一直在运行的解决方案: 使用进入前后台的监听方式,在进入后台时暂停动画的播放,在进入前台后再播放。

- (void)applicationDidBecomeActive{

[self.gifImageView startAnimating];

}

- (void)applicationDidEnterBackground{

[self.gifImageView stopAnimating];

}

- (void)viewDidLoad {

[super viewDidLoad];

[NSNotificationCenter.defaultCenter addObserver:self selector:@selector(applicationDidBecomeActive) name:UIApplicationDidBecomeActiveNotification object:nil];

[NSNotificationCenter.defaultCenter addObserver:self selector:@selector(applicationDidEnterBackground) name:UIApplicationDidEnterBackgroundNotification object:nil];

[super viewDidLoad];

self.view.backgroundColor = UIColor.grayColor;

[self.view addSubview:self.gifImageView];

}

- (UIImageView *)gifImageView {

if (!_gifImageView) {

_gifImageView = [[YYAnimatedImageView alloc] init];

_gifImageView.frame = CGRectMake(0, 0, 200, 200);

_gifImageView.center = self.view.center;

_gifImageView.image = [YYImage imageNamed:@"418k.gif"];

}

return _gifImageView;

}

- (void)dealloc {

[NSNotificationCenter.defaultCenter removeObserver:self];

NSLog(@"销毁了");

}

总结

UIImageView 优点:原生 缺点:性能较差SDWebImage 优点:使用简单方便 缺点:需要引入三方、内存爆炸!!!QExtension 优点:使用简单方便 缺点:需要引入三方、不常用、内存爆炸!!!WKWebView 优点:原生、使用简单、兼容性好 缺点:无明显缺点YYImage 优点:使用简单、兼容性好,可以控制暂停和播放 缺点:需要引入三方,在后台依旧占用线程,需要自己解决一下。QMUI 优点:使用简单,本质就是NSdata转UIImage 缺点:需要引入三方、内存占用很高,无法自由控制播放

素材

学习资料

《iOS 客户端动图优化实践》- 原创 wyanwan 腾讯音乐技术团队 2023-05-09 12:02 《iOS播放GIF动画的几种方式》

相关文章

🪶
鲷鱼读diao还是chou?鱼和周合在一起念什么?
365bet最快线路检测中心

鲷鱼读diao还是chou?鱼和周合在一起念什么?

06-27 👀 4367
🪶
烤箱版‖在家也能轻松做烤鸭
365限制结束投注

烤箱版‖在家也能轻松做烤鸭

06-28 👀 4055