SDWebImage 加载显示 GIF 与性能问题
2017-08-24 10:59
453 查看
转自:http://www.cnblogs.com/silence-cnblogs/p/6682867.html
SDWebImage 4.0 之前,可以用 UIImageView 显示 GIF 图。如果 SDWebImage 4.0 还这么做,只会显示静态图。SDWebImage 4.0 用 FLAnimatedImageView 通过 FLAnimatedImage 显示 GIF 图。本文的这两个库的版本分别为 SDWebImage 4.0.0 和 FLAnimatedImage 1.0.12。
用 FLAnimatedImageView 代替 UIImageView,显示 GIF。FLAnimatedImage 的 README.md 中介绍的用法
千万别这么写,这段代码会阻塞主线程!在主线程通过 URL 获取 NSData,等下载结束才执行下一步。
FLAnimatedImageView 的用法和 UIImageView 相似,初始化、设置 frame、添加到视图上、用 UIImage 给 image 属性赋值显示静态图片;不一样的是,用 FLAnimatedImage 给 animatedImage 属性赋值显示动态图片。以上代码的问题在于 FLAnimatedImage 的生成部分。
SDWebImage 给 FLAnimatedImageView 添加了异步加载 GIF 的方法,与异步加载静态图片一样
如果显示少量的 GIF,这样写应该可以。然而,如果需要用 UITableView 或 UICollectionView 展示大量 GIF,这么写可能会有性能问题,滑动时发生顿卡。
为了提高性能,可以指定 RunLoopMode,在 default mode 进行动画,在 tracking mode (比如 scroll view 滑动时) 停止动画
我的代码中,这么写还是会有顿卡。查看 SDWebImage 的源码,发现了问题。
sd_setImage(with:placeholderImage:) 会调用 sd_internalSetImageWithURL: 方法
注意,sd_internalSetImageWithURL: 方法中的 setImageBlock 参数,在此生成 FLAnimatedImage。进一步查看 sd_internalSetImageWithURL: 方法的实现
宏定义 dispatch_main_async_safe(block) 保证 block 在主线程中执行,其中包含 setImageBlock。因此 setImageBlock 在主线程中执行,也就是说 FLAnimatedImage 在主线程中生成,这一步比较耗时,阻塞主线程,造成顿卡。
解决办法是,把 FLAnimatedImage 的生成放到子线程中。可以直接修改 SDWebImage 的源码,但不建议这么做。比较好的办法是,给 FLAnimatedImageView 添加方法
同样调用 sd_internalSetImageWithURL: 方法,只是修改 setImageBlock 参数,在子线程中创建 FLAnimatedImage,然后在主线程中设置图片。
这个方法也适用于静态图片。如果图片是静态图片,直接在主线程中设置图片,不用进入子线程。
调用这个方法很简单
这样写,UITableView 滑动就很流畅了。
代码已上传 GitHub:https://github.com/Silence-GitHub/GIFDemo
转载请注明出处:http://www.cnblogs.com/silence-cnblogs/p/6682867.html
SDWebImage 4.0 之前,可以用 UIImageView 显示 GIF 图。如果 SDWebImage 4.0 还这么做,只会显示静态图。SDWebImage 4.0 用 FLAnimatedImageView 通过 FLAnimatedImage 显示 GIF 图。本文的这两个库的版本分别为 SDWebImage 4.0.0 和 FLAnimatedImage 1.0.12。
CocoaPods 安装
pod 'SDWebImage' pod 'SDWebImage/GIF'
一般用法
用 FLAnimatedImageView 代替 UIImageView,显示 GIF。FLAnimatedImage 的 README.md 中介绍的用法FLAnimatedImage *image = [FLAnimatedImage animatedImageWithGIFData:[NSData dataWithContentsOfURL:[NSURL URLWithString:@"https://upload.wikimedia.org/wikipedia/commons/2/2c/Rotating_earth_%28large%29.gif"]]]; FLAnimatedImageView *imageView = [[FLAnimatedImageView alloc] init]; imageView.animatedImage = image; imageView.frame = CGRectMake(0.0, 0.0, 100.0, 100.0); [self.view addSubview:imageView];
千万别这么写,这段代码会阻塞主线程!在主线程通过 URL 获取 NSData,等下载结束才执行下一步。
FLAnimatedImageView 的用法和 UIImageView 相似,初始化、设置 frame、添加到视图上、用 UIImage 给 image 属性赋值显示静态图片;不一样的是,用 FLAnimatedImage 给 animatedImage 属性赋值显示动态图片。以上代码的问题在于 FLAnimatedImage 的生成部分。
SDWebImage 给 FLAnimatedImageView 添加了异步加载 GIF 的方法,与异步加载静态图片一样
imageView.sd_setImage(with: url, placeholderImage: placeholder)
如果显示少量的 GIF,这样写应该可以。然而,如果需要用 UITableView 或 UICollectionView 展示大量 GIF,这么写可能会有性能问题,滑动时发生顿卡。
提升性能
为了提高性能,可以指定 RunLoopMode,在 default mode 进行动画,在 tracking mode (比如 scroll view 滑动时) 停止动画imageView.runLoopMode = RunLoopMode.defaultRunLoopMode.rawValue
我的代码中,这么写还是会有顿卡。查看 SDWebImage 的源码,发现了问题。
sd_setImage(with:placeholderImage:) 会调用 sd_internalSetImageWithURL: 方法
注意,sd_internalSetImageWithURL: 方法中的 setImageBlock 参数,在此生成 FLAnimatedImage。进一步查看 sd_internalSetImageWithURL: 方法的实现
宏定义 dispatch_main_async_safe(block) 保证 block 在主线程中执行,其中包含 setImageBlock。因此 setImageBlock 在主线程中执行,也就是说 FLAnimatedImage 在主线程中生成,这一步比较耗时,阻塞主线程,造成顿卡。
解决办法是,把 FLAnimatedImage 的生成放到子线程中。可以直接修改 SDWebImage 的源码,但不建议这么做。比较好的办法是,给 FLAnimatedImageView 添加方法
extension FLAnimatedImageView { func setImage(with url: URL?, placeholderImage: UIImage?) { sd_internalSetImage(with: url, placeholderImage: placeholderImage, options: SDWebImageOptions(rawValue: 0), operationKey: nil, setImageBlock: { [weak self] (image, imageData) in guard let strongSelf = self else { return } let imageFormat = NSData.sd_imageFormat(forImageData: imageData) if imageFormat == .GIF { // Enter global queue DispatchQueue.global(qos: .userInteractive).async { [weak self] in // Create FLAnimatedImage in global queue let animatedImage = FLAnimatedImage(animatedGIFData: imageData) DispatchQueue.main.async { [weak self] in guard let strongSelf = self else { return } // Set image in main queue strongSelf.animatedImage = animatedImage strongSelf.image = nil } } } else { // Set image in main queue strongSelf.image = image strongSelf.animatedImage = nil } }, progress: nil, completed: nil) } }
同样调用 sd_internalSetImageWithURL: 方法,只是修改 setImageBlock 参数,在子线程中创建 FLAnimatedImage,然后在主线程中设置图片。
这个方法也适用于静态图片。如果图片是静态图片,直接在主线程中设置图片,不用进入子线程。
调用这个方法很简单
imageView.setImage(with: url, placeholderImage: placeholder)
这样写,UITableView 滑动就很流畅了。
代码已上传 GitHub:https://github.com/Silence-GitHub/GIFDemo
转载请注明出处:http://www.cnblogs.com/silence-cnblogs/p/6682867.html
相关文章推荐
- SDWebImage 加载显示 GIF 与性能问题
- SDWebImage 加载显示 WebP 与性能问题
- iOS开发-SDWebImage4.0之后加载gif不显示的解决方案(FLAnimatedImageView FLAnimatedImage)
- iOS 使用SDWebImage加载gif链接图片时内存过大问题
- ios-使用SDWebImage加载Gif图片的问题
- SDWebImage 加载图片不显示问题 --- 难以想象的BUG
- SDWebImage 加载图片不显示问题
- SDWebImage加载图片问题
- SDWebImage加载图片URL第一次失败,后面图片URL存在不刷新的问题
- 解决MWPhotoBrowser中的SDWebImage加载大图导致的内存警告问题
- 解决使用SDWebImage加载图片,图片为空的问题
- 解决MWPhotoBrowser中的SDWebImage加载大图导致的内存警告问题
- 解决MWPhotoBrowser中的SDWebImage加载大图导致的内存警告问题
- SDWebImage加载gif超级耗内存
- 使用SDWebImage解决头像不显示问题
- 解决MWPhotoBrowser中的SDWebImage加载大图导致的内存警告问题(刚刚)
- 解决MWPhotoBrowser中的SDWebImage加载大图导致的内存警告问题解决方案参考
- 解决MWPhotoBrowser中的SDWebImage加载大图导致的内存警告问题
- 解决MWPhotoBrowser中的SDWebImage加载大图导致的内存警告问题
- 完美解决SDWebImage加载多个图片内存崩溃的问题