swift - 我应该怎么做才能在tableView中加载异步图像?

标签 swift image asynchronous tableview dispatch

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

我使用的是 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)
    }
}

在我的 TableView Controller 中,我使用此功能下载图像

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
    }

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

最佳答案

我认为你有两个选择

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

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

如果您下载所有图像会增加应用程序的内存使用量,如果使用过多,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)
    }
}

关于swift - 我应该怎么做才能在tableView中加载异步图像?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57048203/

相关文章:

ios - Use of unresolved identifier 'scope' 为什么这个错误会出现在下面的代码中

ios - 如何让UIImage变圆

.net - 实现扩展方法 WebRequest.GetResponseAsync 并支持 CancellationToken

下载 Alamofire 后快速保存文件

iOS - 存储供 AppDelegate 和其他 View Controller 使用的数据

java - 在Android上读取jpeg文件的量化表

html - 火狐渲染背景图

css:将图像链接到 url

c# - 如何以及何时使用 ‘async’ 和 ‘await’

c# - 为什么同步上下文不适用于等待?