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

what should I do to load asynchronous images in tableView?

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

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

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

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)
    }
}

大哥,你怎么不用第三方库啊? Sd_webimage, Kingfisher 你可以只 pod 这个库中的一个并且在一行代码中你的图像在你想要的 tableview 索引处可见。

我会推荐使用第三方库在 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
            }
        }

平滑滚动表格视图需要此代码。

cell.layer.shouldRasterize = true
cell.layer.rasterizationScale = UIScreen.main.scale

I am downloading 5000 images and showing them in the table view.