SDWebImage在Cell里的使用,回调后刷新tableView并防止死循环

背景:

最近有个需求:根据图片url连接是否合法,好比连接贴错了,多了或者少了一些字符等状况,就会致使图片加载失败,遇到这种状况,就须要隐藏掉cell里的UIImageView。缓存

先看看这个Cell长得怎样:红框部分就是这个cell要显示的内容,1个红点UIView + 2个UILabel + 1个UIImageView。(考虑到有个红点不方便对齐,因此没有使用UIStackView)markdown

image.png

实现思路:

  • 在cell的init方法里,默认让dateLabel底部距离父视图16的间距,而让photoView底部距离父视图16的间距约束失效:闭包

    dateLabel.snp.makeConstraints {
        ...
        dateLabelBottomConstraint = $0.bottom.equalToSuperview().inset(16).constraint
    }
    
    photoView.snp.makeConstraints {
        ...
        photoViewBottomConstraint = $0.bottom.equalToSuperview().inset(16).constraint
    }
    
    photoViewBottomConstraint?.deactivate()
    复制代码
  • 在cell的setupPhotoViewImage()方法里,传递图片URL,根据加载图片结果,判断URL是否有效,再改变dateLabelBottomConstraintphotoViewBottomConstraintisHidden,从而决定图片是否显示。ide

    • 先使用SDImageCache.shared.imageFromCache(forKey:)去拿SDWebImage缓存的image,若是拿到了,就直接让photoView显示image。布局

    • 若是没拿到缓存,则用sd_setImage去请求图片,在请求完成的回调闭包里面,判断image若是不为nil,则使用代理让外部view controller刷新当前的cell。(SDWebImage在此步会自动缓存图片,无需手动再缓存)url

    • 上述2小步,就避免了刷新cell的时候又再会去执行sd_setImage,防止请求图片完成又刷新,致使死循环。spa

    func setupPhotoViewImage(inboxMediaURL: URL?) {
        guard let cacheImage = SDImageCache.shared.imageFromCache(forKey: inboxMediaURL.absoluteString) else {
            photoView.sd_setImage(with: inboxMediaURL) {
                [weak self] image, _, _, _ in
                guard let self = self, image != nil else { return }
                self.delegate?.reloadCellData(self)
            }
            return
        }
        photoView.image = cacheImage
        showImage()
    }
    
    private func showImage() {
        photoView.isHidden = false
        dateLabelBottomConstraint?.deactivate()
        photoViewBottomConstraint?.activate()
    }
    复制代码
  • 设置prepareForReuse(),默认中止图片请求,并隐藏图片,防止连续滚动的时候产生布局问题。代理

    这里使用了sd_cancelCurrentImageLoad()是为了防止cell复用的过程当中请求图片发生问题。由于cell的setupPhotoViewImage方法里先去拿cache,没有拿到才会调用sd_setImage,而 sd_setImage 源码里是有调用了sd_cancelCurrentImageLoad()的,滑动屏幕,cell复用的时候,有些cell有可能不会去调用sd_setImage的,这样就没有中止加载cell里的图片,而这时以前的图片加载完成,就会将图片显示到后续复用了的cell里。code

    override func prepareForReuse() {
        super.prepareForReuse()
        photoView.sd_cancelCurrentImageLoad()
        hideImage() 
    }
    
    private func hideImage() {
        photoView.isHidden = true
        photoViewBottomConstraint?.deactivate()
        dateLabelBottomConstraint?.activate()
    }
    复制代码
相关文章
相关标签/搜索