美文网首页
SDWebImage 加载显示 GIF 与性能问题

SDWebImage 加载显示 GIF 与性能问题

作者: Jelly_沫 | 来源:发表于2018-01-22 17:56 被阅读0次

    SDWebImage 加载显示 GIF 与性能问题

    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:[NSDatadataWithContentsOfURL:[NSURLURLWithString:@"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{

    funcsetImage(with url: URL?, placeholderImage: UIImage?){        sd_internalSetImage(with: url, placeholderImage: placeholderImage, options:SDWebImageOptions(rawValue:0), operationKey:nil, setImageBlock: { [weakself] (image, imageData)inguardletstrongSelf =selfelse{return}letimageFormat =NSData.sd_imageFormat(forImageData: imageData)ifimageFormat == .GIF{// Enter global queueDispatchQueue.global(qos: .userInteractive).async { [weakself]in// Create FLAnimatedImage in global queueletanimatedImage =FLAnimatedImage(animatedGIFData: imageData)DispatchQueue.main.async { [weakself]inguardletstrongSelf =selfelse{return}// Set image in main queuestrongSelf.animatedImage = animatedImage                        strongSelf.image =nil}                }            }else{// Set image in main queuestrongSelf.image = image                strongSelf.animatedImage =nil}            }, progress:nil, completed:nil)    }}

    同样调用 sd_internalSetImageWithURL: 方法,只是修改 setImageBlock 参数,在子线程中创建 FLAnimatedImage,然后在主线程中设置图片。

    这个方法也适用于静态图片。如果图片是静态图片,直接在主线程中设置图片,不用进入子线程。

    调用这个方法很简单

    imageView.setImage(with: url, placeholderImage: placeholder)

    相关文章

      网友评论

          本文标题:SDWebImage 加载显示 GIF 与性能问题

          本文链接:https://www.haomeiwen.com/subject/vlazsxtx.html