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()
    }
    複製代碼
相關文章
相關標籤/搜索