首页 > 解决方案 > 我应该怎么做才能在 tableView 中加载异步图像?

问题描述

好吧,我应该在表格视图中加载图像,我下载并加载成功,但是当我尝试在表格视图中显示时,它们没有出现,但是,如果我在表格视图中滚动,图像会出现但是图像不会在单元格的中间。

我正在使用 swift 4.2

这行帮助我下载并加载了图像

extension UIImageView {
    func downloaded(from url: URL, contentMode mode: UIView.ContentMode = .scaleAspectFit) {  
        contentMode = mode
        URLSession.shared.dataTask(with: url) { data, response, error in
            guard
                let httpURLResponse = response as? HTTPURLResponse, httpURLResponse.statusCode == 200,
                let mimeType = response?.mimeType, mimeType.hasPrefix("image"),
                let data = data, error == nil,
                let image = UIImage(data: data)
                else { return }
            DispatchQueue.main.async() {
                self.image = self.resizedImageWith(image: image, targetSize: CGSize(width: 100.0, height: 50.0))
            }
            }.resume()
    }
    func downloaded(from link: String, contentMode mode: UIView.ContentMode = .scaleAspectFit) {  
        guard let url = URL(string: link) else { return }
        downloaded(from: url, contentMode: mode)
    }
}

在我的表格视图控制器中,我使用此功能下载图像

func loadImages()
    {
        for img in arrFavServices
        {
            if let url = img?.logo
            {
                let imgDownload = UIImageView()
                imgDownload.downloaded(from: url, contentMode: .redraw)
                arrImages.append(imgDownload)
            }
            else
            {
                let imgDownload = UIImageView()
                imgDownload.image = UIImage(named: "logo")
                arrImages.append(imgDownload)
            }
          tableView.reloadData()
          tableView.layoutIfNeeded()
          tableView.layoutSubviews()
          utilActivityIndicator.shared.hideLoader(view: view)
        }
    }

数组 arrFavServices 包含所有图像的 url,而 arrImages 包含之前下载的所有图像。在 viewdidload 中调用了函数 loadImages。我使用这个功能来显示图像

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
        if (arrFavServices[indexPath.section]?.logo) != nil
        {
            if arrImages[indexPath.section].image != nil
            {
                cell.imageView?.image = arrImages[indexPath.section].image
                cell.imageView?.contentMode = .center
            }
        }
        // Configure the cell...
        if let color = arrFavServices[indexPath.section]?.color
        {
            cell.backgroundColor = UIColor(hexString: color)
        }
        return cell
    }

我的错误是什么?请帮帮我

标签: swiftimageasynchronoustableviewdispatch

解决方案


我认为你有两个选择

  • 当单元格可见时,您会异步下载图像(我推荐)

  • 下载所有图像并显示单元格可见

如果您下载所有图像会增加应用程序的内存使用量,如果使用过多,iOS 将使您的应用程序崩溃。

第一条路径:

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
    if let logo = arrFavServices[indexPath.section]?.logo {
        // We need download image here
        cell.imageView?.downloaded(from: logo, contentMode: .center)
    }

    // Configure the cell...
    if let color = arrFavServices[indexPath.section]?.color {
        cell.backgroundColor = UIColor(hexString: color)
    }
    return cell
}

第二条路径:

您可以使用调度组。UITableView 正在等待下载所有图像。

// Cache array
var downloadedImages: [UIImage] = []

// Create an instance
var dispatchGroup = DispatchGroup()


func loadImages() {

    // Every tick of loop, we enter the group
    for img in arrFavServices {

        // Join the group
        dispatchGroup.enter()
        if let url = img?.logo {
            let imgDownload = UIImageView()
            imgDownload.downloaded(from: url, contentMode: .redraw, completion: { [weak self] downloadedImage in
                guard let self = self else { return }
                self.downloadedImages.append(downloadedImage)

                // And leave group when task is done
                dispatchGroup.leave()

            })
        } else {
            let imgDownload = UIImageView()
            imgDownload.image = UIImage(named: "logo")
            arrImages.append(imgDownload)

            // We can leave here too because we add image to array
            dispatchGroup.leave()
        }

    }

    // We have to listen group, and that we update tableView or UI todo
    dispatchGroup.notify(queue: .main) {
        self.tableView.reloadData()
        self.tableView.layoutIfNeeded()
        self.tableView.layoutSubviews()
        self.utilActivityIndicator.shared.hideLoader(view: self.view)
    }
}

您可以设置完成处理程序,如下所示

extension UIImageView {
    func downloaded(from url: URL, contentMode mode: UIView.ContentMode = .scaleAspectFit, completion: ((UIImage) -> Void)?) {
        contentMode = mode
        URLSession.shared.dataTask(with: url) { data, response, error in
            guard
                let httpURLResponse = response as? HTTPURLResponse, httpURLResponse.statusCode == 200,
                let mimeType = response?.mimeType, mimeType.hasPrefix("image"),
                let data = data, error == nil,
                let image = UIImage(data: data)
                else { return }
            DispatchQueue.main.async() {
                completion?(image)
            }
            }.resume()
    }
    func downloaded(from link: String, contentMode mode: UIView.ContentMode = .scaleAspectFit, completion: ((UIImage) -> Void)?) {
        guard let url = URL(string: link) else { return }
        downloaded(from: url, contentMode: mode, completion: completion)
    }
}

推荐阅读