【问题标题】:Swift: Array Struct Image not visible in TableViewSwift:数组结构图像在 TableView 中不可见
【发布时间】:2020-08-28 12:14:21
【问题描述】:

我又问了一个新问题。 我正在从一些 JSON 中收集图片数据,并将其填充到一个以 Struct 作为数据类型的数组中。 一切正常,但是当我尝试在 TableView 中显示它时,图像丢失 - 其余数据正在按需要显示。 但是图像似乎也存储在数组中(请参阅警卫后的打印---添加了新图片---)。 Dispatch Group 也完成了“All Done”。 如果您能看一下并告诉我我做错了什么,那就太好了。

数组:

var memeRawData: [MemeRawData] = []

结构:

struct MemeRawData {
    let name: String?
    let url: String?
    let img: UIImage?
}

调度组从 JSON 中收集数据并下载图像并将其附加到数组中:

        var meme = MemeRawData(name: "", url: "", img: UIImage())
        var memeName = ""
        var memeURL = ""
        var memeIMG = UIImage()

        let g = DispatchGroup()
            MemeAPI.requestAPIImageData { (imgData, error) in
                imgData?.data.memes.forEach{
                    memeData in
                    g.enter()
                    memeName = memeData.name!
                    memeURL = memeData.url!
                    MemeAPI.requestAPIImageFile(url: URL(string: memeData.url!)!) { (image, error) in
                        guard let image = image else {
                            print("PIC IS NIL")
                            return
                        }
                        memeIMG = image
                        print("-----NEW PIC ADDED-------")
                    }

                    meme = MemeRawData(name: memeName, url: memeURL, img: memeIMG)

                    self.memeRawData.append(meme)

                    g.leave()
                    }
                g.notify(queue:.main) {
                print("All done")
                }
        }

从 URL 获取图片的函数:

class func requestAPIImageFile(url: URL, completionHandler: @escaping (UIImage?, Error?) -> Void) {
    let task = URLSession.shared.dataTask(with: url) { (data, response, error) in
        guard let data = data else {
            completionHandler(nil, error)
            return}
        let downloadedImage = UIImage(data: data)
        completionHandler(downloadedImage, nil)
    }
    task.resume()
}

并完成它的tableView dequeue:

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "memeAPICell")

    cell?.textLabel?.text = memeRawData[indexPath.row].name
    cell?.imageView?.image = memeRawData[indexPath.row].img

    return cell!
}

就像我说的 JSON 解析工作正常,因为我可以显示所有 URL 和名称 - 但图像似乎有问题。控制台也没有打印出任何错误。

提前致谢!

【问题讨论】:

  • 只是时间问题吗?如果图像是在 tableview 显示后下载的,那么你需要在数据到达时刷新 tableview 的每一行
  • 我同意@Ru​​ssell。当您尝试创建“MemeRawData”对象时,图像尚未下载。
  • @Russell 感谢您的意见!这也是有道理的。有没有办法“保持”直到图像被下载并可以存储在对象中?我对 swift 很陌生
  • 最好的方法是展示你拥有的东西,然后再更新——我们不想保留任何东西。在 'cellForRowAt' 中,我们应该检查图像是否可用 - 如果有,则显示它,如果没有,则显示'即将推出的图像...图片',然后在数据到来时刷新特定行。如果没有人超过我,我将很快分享一个例子
  • @Russell 那太好了!非常感谢!

标签: json swift uiimage tableview urlsession


【解决方案1】:

需要在主线程中设置图片,

编写这个函数,

 func setImage(imageView:UIImageView,url:URL){
        let task = URLSession.shared.dataTask(with: url){ (data, response, error) in
            if error != nil{
                return
            }
            DispatchQueue.main.async {
                let img = UIImage(data: data!)
                imageView.image = img
            }
        }
        task.resume()
    }

然后在 cellForItemAt

中调用它
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "memeAPICell")

    cell?.textLabel?.text = memeRawData[indexPath.row].name
    self.setImage(imageView:cell!.imageView!, url: URL(string: memeRawData[indexPath.row].url)!)

    return cell!
}

【讨论】:

  • 嘿,谢谢,这显示了正确的图像,但我希望我可以在数组中预加载图像,因为现在当我导航到 TableView 时,下载开始并且有一点等待直到所有图像都显示的时间。这就是为什么我试图将它们存储在一个数组中,并且只在导航到 TableView 时传递它们是否也有解决方案?
【解决方案2】:

设置您的数据数组,然后为每个元素下载图像。第一次显示 tableview 时它不可用,但没关系。您可以选择如何表明某事即将发生,这是一种简单的方法。

override func viewDidLoad() {
    super.viewDidLoad()

    // set up your meme data as you do already

    // go get images in the background
    for index in 0...memeRawData.count-1 {
        print("Go get data for \(index)")
        getImage(index: index, url: URL(string: memeRawData[index].url ?? "")!)
    }
}

func getImage(index: Int, url:URL){
    let task = URLSession.shared.dataTask(with: url){ (data, response, error) in
        if error != nil{
            return
        }
        DispatchQueue.main.async {
            print("ready to reload /(index)")
            // now that you have the image, add it to your data array
            self.memeRawData[index].img = UIImage(data: data!)
            // now reload the specific row in your tableview
            self.tableView.reloadRows(at: [IndexPath(row: index, section: 0)], with: .automatic)
        }
    }
    task.resume()
}

那么您所要做的就是修改显示表格视图单元格的方式。在此示例中,如果没有可用的图像,我已更改文本显示,但您可以将图像替换为图片以显示等待,如果您的资产中包含该图像,则可以显示它。

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "memeAPICell")

    if memeRawData[indexPath.row].img == nil
    {
        cell?.textLabel?.text = memeRawData[indexPath.row].name! + " awaiting image ..."
    }
    else
    {
        cell?.textLabel?.text = memeRawData[indexPath.row].name ?? "title"
    }
    cell?.imageView?.image = memeRawData[indexPath.row].img

    return cell!
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-12-25
    • 1970-01-01
    • 2015-10-01
    • 1970-01-01
    • 1970-01-01
    • 2023-01-26
    相关资源
    最近更新 更多