swift 4 tableViewCell动态加载网络图片问题处理

1. 很多APP都会涉及到资讯或帖子或主题详情页的界面,其中就涉及到cell加载网络图片的开发问题.

2. 最容易想到的思路就是把URL直接传递给cell,让cell的imageView控件直接使用SDWebImage下载,然后去展示. 这个思路看似正常不过,但是会有问题.

  • 问题1: cell下载好图片后如何更新, 更新逻辑处理不好容易形成死循环: 下载--更新--触发下载--有触发更新.....
  • 问题2: 即使用一定方式如: 设置变量阻断死循环, 又会引发另一个问题-- cell的复用问题, 从网路下载的图片,尺寸都不一样,通过等比例缩放后,虽然等宽,但是高度都不相等, 多个cell展示多个图片的时候,滑动的时候会有复用的问题,导致图片高度出问题. 即使缓存了图片的高度也会出现其他问题

3. 只有另寻处理, 把图片的下载挪到controller中去处理, 利用SDWebImageDownloader下载图片, 利用SDImageCache去缓存下载的图片. 每次加载cell时,先判断SDImageCache缓存中有没有对应的图片,如果有取出来给cell展示, 如果没有就去下载, 下载利用SDImageCache去缓存, 然后更新下载的图片. 就完美解决了, cell动态加载图片的问题

1. 首先是自定义cell用来展示图片

import UIKit

let imageCellMargin:CGFloat = 15.0

class ImageCell: UITableViewCell {
    // 无论加载成功和失败,都传递一张图片过来,加载成功传递下载的图片,加载失败传递占位图片
    var img: UIImage? {
        didSet {
            if let img = img {
                imgView.image = img

                //图片尺寸处理,这里仅仅简单等比例处理, 更复杂的图片尺寸处理不是本次讨论的重点
                let width = UIScreen.main.bounds.size.width - 2 * imageCellMargin
                let height = img.size.height * (width / img.size.width)
                //更新图片尺寸
                imgView.snp.remakeConstraints { (make) in
                    make.top.equalTo(contentView.snp.top)
                    make.height.equalTo(height).priority(900)
                    make.left.equalTo(contentView.snp.left).offset(imageCellMargin)
                    make.right.equalTo(contentView.snp.right).offset(-imageCellMargin)
                    make.bottom.equalTo(contentView.snp.bottom).offset(-10)
                }
            }
        }
    }

    override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
        super.init(style: style, reuseIdentifier: reuseIdentifier)
        contentView.addSubview(imgView)
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    //懒加载
    lazy var imgView:UIImageView = {
        let imgView = UIImageView()
        return imgView
    }()
}

2. tableView注册cell

这里写图片描述

3. tableView的数据源方法中处理cell

  • 如果是图片的cell, 就调用配置cell的方法
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        ## 设置复用标识reuseIdentifier
        var reuseIdentifier = ""
        if () {
            reuseIdentifier = "reuseIdentifierOther"
        } else {
            reuseIdentifier = "reuseIdentifierImage"
        }
        ## 根据判断条件创建cell
        let cell = tableView.dequeueReusableCell(withIdentifier: reuseIdentifier, for: indexPath)
        ## 判断出不同类型的cell
        if () {
        } else {//图片
            setImageCell(imageCell: (cell as! ImageCell), indexPath: indexPath)
        }

        return = cell
    }



    //配置图片的方法
    func setImageCell(imageCell: ImageCell, indexPath: IndexPath) -> () {
        //取出对应的图片链接
        let imageUrl = imageUrlArr[indexPath.row - 2]
        //SDImageCache取出对应链接缓存的图片
        let cachedImage = SDImageCache.shared().imageFromDiskCache(forKey: "\(imageUrl)")
        if cachedImage == nil {
            //如果没有对应的缓存图片就去下载
            downLoadImage(imageUrl: imageUrl, indexPath: indexPath)
            //将占位图片传递过去
            imageCell.img = UIImage.init(named: "image_placeholder")
        } else {
            //如果能取出缓存的图片,就将取到的图片赋值过去展示
            imageCell.img = cachedImage
        }
    }

    //下载图片
    func downLoadImage(imageUrl: URL, indexPath: IndexPath) -> () {
        SDWebImageDownloader.shared().downloadImage(with: imageUrl, options: .useNSURLCache, progress: { (receivedSize, expectedSize, url) in
            //下载进度
        }) { (image, data, error, finished) in
            //下载完毕存储图片
            if error == nil {
                SDImageCache.shared().store(image, forKey: "\(imageUrl)", toDisk: true, completion: nil)
                DispatchQueue.main.async {
                    self.performSelector(onMainThread: #selector(self.reloadImageCell(indexPath:)), with: indexPath, waitUntilDone: false)
                }
            } else {//针对其他情况处里
                return
            }
        }
    }

    //刷新
    func reloadImageCell(indexPath: IndexPath) -> () {
        self.tableView.reloadRows(at: [indexPath], with: .none)
    }

4. 效果

//下载好的图片
这里写图片描述

//占位图和已下载号的图片
这里写图片描述

猜你喜欢

转载自blog.csdn.net/kuangdacaikuang/article/details/80687004