项目介绍:
UIImageView显示GIF图问题
主题 《iOS开发》 by evan
导语
以前对GIF图的显示没有太多关注,端上使用UIImageView+SDWebImage的方式下载显示GIF也没暴露出问题。最近突然测试找到我报了一个Bug,开始以为很简单,随后我的一天时间都花在解这个Bug上,所以记录一下,有需要的同学可以借鉴参考。
一.发现Bug
这个Bug大概是这样子的:
首先gif图是能正常显示,一旦侧滑VC,或者滚动table,gif图就消失不见。
尽管我们对组件封装了很多层(富文本解析,重新绘制…),本质上,我们还是使用UIImageView来展示图片,这里的图片资源也分很多种(相册里的,mainBundle里的,document里面的,网络图片), 这里主要说一下通过网络获取的图片,我们下载图片的组件跟大家用的一样,是SDWebImage。
- (void)sd_setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder options:(SDWebImageOptions)options progress:(SDWebImageDownloaderProgressBlock)progressBlock completed:(SDWebImageCompletionBlock)completedBlock;
二.分析问题
1.是否是数据出问题
经过数据抓包排查,数据源并没有问题,该图片确实存在,且网址能正确访问到:
GIF图地址
2.是否是绘制出问题
通过断点调试排查,确认也不是绘制的问题,侧滑返回的时候并没有出发reload操作。
3.是否是UIImageView不支持显示GIF
查看UIImageView的API,里面没有明确说支持还是不支持GIF,能知道的是,他可以显示单个UIImage,可以显示一组UIImage。
而我们通过地址下载下来的是一个UIImage,不过这个UIImage的images数组里面是一组数据,本质上就是一个GIF图。
现在问题比较明朗,不是数据问题,不是绘制问题,下载下来的UIImage也没问题,那问题肯定是出在UIImageView上。
UIImageView显示GIF的本质是不停的去刷新换图,但这种绘制操作肯定是消耗资源的,所以在用户与界面有交互的时候,为了保证界面的流畅,该操作应该会被挂起,也就是说,这种操作应该不是一直在NSDefaultRunLoopMode中,感兴趣的朋友可以认真去了解一下NSRunLoop。
三.解决问题
1.简单解决
如果你的app是不在乎支不支持GIF的,你可以把GIF转成PNG展示,也就不会有这个问题。
2.彻底解决
写一个UIImageView的category,如果是GIF图,就控制在恰当的时机切换不同的mode,展示图片还是GIF,这样的工作呢,很多前辈已经替我们做了,github搜索就能有,比如:UIImageView-PlayGIF
我用的时候还遇到点问题,UIImageView-PlayGIF提供了两个API,一个是加载本地的GIF,一个是把GIF的NSData数据给进去,这就尴尬了。通过sd_setImageWithURL下载,回调里面并没有提供NSData,给的是一个UIImage:
typedef void(^SDWebImageCompletionBlock)(UIImage *image, NSError *error, SDImageCacheType cacheType, NSURL *imageURL);
怎么办?
把UIImage转化为NSData,但是试过很过方法,转完之后就不是GIF了,而是PNG了,所以必须另求出路。
采用SDWebImageDownloader下载,回调里面会有NSData
只是,你会发现采用SDWebImageDownloader下载,界面显示就是没有sd_setImageWithURL方法流畅,这是因为sd_setImageWithURL里面对cache和线程做了很多处理,保证了UI的流畅。
所以,如果你觉得自己有时间有精力,可以把处理cache和线程的逻辑写在SDWebImageDownloader的回调里,也就满足了。
如果想偷懒也行,sd_setImageWithURL回调的时候不用image,去直接读cache(首先是小猿我了解sd_setImageWithURL里的内部逻辑,下载完之后先入cache,再执行block,这才保证外面可以直接读取到),取出来的就是NSData:
至此,这个Bug就解决了!