如何在tableView中加载异步图像?

时间:2019-07-15 23:17:53

标签: swift image asynchronous tableview dispatch

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

我正在使用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
    }

我的错误是什么?请帮忙

3 个答案:

答案 0 :(得分:3)

我认为您有2个选择

  • 当单元格可见时,您将异步下载图像(我建议)

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

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

答案 1 :(得分:0)

伴侣,您为什么不使用第三方库? Sd_webimage,Kingfisher,您可以仅挂载该库之一,并且在一行代码中,可以在所需的tableview索引处看到图像。

答案 2 :(得分:0)

我会推荐使用第三方库在 tableview 中加载图像。

在 podfile 中添加这个。

pod 'SDWebImage'

在 cellForRowAtIndex 中添加这个简单的代码

 func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
            
            if(indexPath.row > arrId.count-1){
                // This will return an empty cell if all data is not downloaded and it will avoid the fatal error: index out of range
                return UITableViewCell()
            }
            else{
                let cell = tableView.dequeueReusableCell(withIdentifier: "AlbumCustomCell", for: indexPath) as! AlbumCustomCell
                cell.lblId.text = String ( self.arrId[indexPath.row] )
                cell.lblTitle.text = self.arrAlbumTitleString[indexPath.row]
                
                cell.layer.shouldRasterize = true
                cell.layer.rasterizationScale = UIScreen.main.scale
                
                if let url =  URL(string: self.arrAlbumThumbnailURLString[indexPath.row]) {
                    cell.albumThumbnaiilImage.sd_setImage(with: url, placeholderImage: UIImage(named: "placeholder"), options: .continueInBackground, context: nil)
                }
                return cell
            }
        }

平滑滚动tableview需要此代码。

cell.layer.shouldRasterize = true
cell.layer.rasterizationScale = UIScreen.main.scale
<块引用>

我正在下载 5000 张图片并在表格视图中显示它们。