【问题标题】:Cell not showing image after loaded from Firebase Swift从 Firebase Swift 加载后单元格不显示图像
【发布时间】:2018-05-25 03:39:48
【问题描述】:

我有一个 UITableViewCell 显示图像或文本。我已将 UIImageView 的高度和宽度设置为

现在我的问题是,加载后单元格不显示图像,用户需要返回并再次查看此屏幕才能看到图像。我该如何解决?

图片加载前:

图片加载成功后:

如你所见,它没有显示,只是视图被扩展了

如果用户按下 BACK 并再次出现在此视图中,

图像现在显示。

我应该如何解决这个问题?因为我无法在 tableviewcell 中写 tableview.reloaddata()

为我的 tableviewcell 中的代码配置我的单元格:

func configCell(message: Message) {

    self.message = message

    if message.fromId == currentUser {

        sentView.isHidden = false

        sentMsgLabel.text = message.textMessages

        receivedMsgLabel.text = ""

        receivedView.isHidden = true

        timeReceived.text = ""

        timeSent.text = message.timestamp

        youLabel.text = "You"

        themLabel.text = ""


        if let ImageUrl = message.imageUrlLink {

            self.receivedimg.loadImageUsingCacheWithUrlString(ImageUrl)
        }
        }

        else {

        sentView.isHidden = true

        sentMsgLabel.text = ""

        receivedMsgLabel.text = message.textMessages

        receivedMsgLabel.isHidden = false

        timeReceived.text = message.timestamp

        timeSent.text = ""

        // setting name for receipient
        Database.database().reference().child("users").child(message.fromId!).child("name").observe(.value) { (datasnapshot) in
        if let name = datasnapshot.value as? String {
                self.themLabel.text = name
            }
        }

        youLabel.text = ""
    }
}

对于我的 loadImageUsingCacheWithUrlString 代码,扩展名如下:

let imageCache = NSCache<AnyObject, AnyObject>()

    extension UIImageView {

    func loadImageUsingCacheWithUrlString(_ urlString: String) {

        self.image = nil

        //check cache for image first
        if let cachedImage = imageCache.object(forKey: urlString as AnyObject) as? UIImage {
            self.image = cachedImage
            return
        }

        //otherwise fire off a new download
        let url = URL(string: urlString)
        URLSession.shared.dataTask(with: url!, completionHandler: { (data, response, error) in

            //download hit an error so lets return out
            if error != nil {
                print(error ?? "")
                return
            }

            DispatchQueue.main.async(execute: {

                if let downloadedImage = UIImage(data: data!) {
                    imageCache.setObject(downloadedImage, forKey: urlString as AnyObject)

                    self.image = downloadedImage
                }
            })

        }).resume()
    }

}

【问题讨论】:

  • 提供你的代码,让我们看看你如何在图像加载后更新 ImageView
  • loadImageUsingCacheWithUrlString 自定义函数吗?
  • 是的,它是一个将我的图像保存为缓存的功能,因此用户每次打开视图时都不需要加载它
  • 但它会在第一次调用时下载实际图像吗?
  • 是的,它会下载。我的图片已下载,但它不会自动显示,除非我点击返回,然后返回视图

标签: ios swift firebase uicollectionviewcell firebase-storage


【解决方案1】:

下载图片后你的问题很明显,你的单元格没有及时更新,在你的单元格中尝试 self.setNeedDisplays()。它告诉您的单元格应该在下一个视图周期中更新。

我建议您使用 KingFisher 框架,而不是自己加载和捕获自己,它几乎可以完成我们处理远程服务器图像所需的一切:下载、捕获、预取......并且下载后立即显示您的图像强>

【讨论】:

  • 我在我的单元格中添加了 self.setNeedDisplay 但它没有任何效果。将尝试研究 KingFisher 框架
  • setNeedDisplay:直到下一个绘图周期才真正重绘视图,此时所有无效的视图都会更新。因此,当您的视图仍停留在当前周期时,您可能会很不走运。
  • 您可以推荐任何其他参考资料吗?翠鸟没用。我认为是由于我的 tableview 高度是在加载图像之前加载和设置的,因此图像被隐藏了
  • 哦,这对任何 iOS 开发人员来说都是常见问题,方法 heightForCellAtIndex 总是在 cellForRowOfIndex 之前调用。面对这个问题的方法很多。最简单的方法是将 tableView 作为属性存储在单元格中,然后调用 tableView.reloadCellAtIndexPath。更好的方法是在你的 cell 类中实现一个静态函数,尝试计算你的 cell 高度,将它返回到 heightForRowAtIndex 中,如果你想要缓存它们。
  • 面对这个问题你有什么建议?
【解决方案2】:

尝试了很多方法,最后..在我的ViewDidload中,我只是加了一个延迟

 DispatchQueue.main.asyncAfter(deadline: .now() + 1){
        self.tableView.reloadData()
    }

需要延迟。没有它,它就行不通。我假设这是由于在图像完成加载之前设置和加载了单元格高度,所以 tablecell 不知道需要多少高度,这就是为什么我们需要在延迟 1 秒后重新加载 tableview

【讨论】:

    【解决方案3】:

    UITableViewCell里面做action而不是在cellForRowAt里面做action

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        //Your actuions here
    }
    

    然后你可以在你的UITableViewController 中使用tableView.reloadData()

    希望这将有助于解决您的问题。

    【讨论】:

    • 我猜 OP 从 cellForRowAt 调用 configCell 函数?所以它应该工作
    • 所以我从 cellForRowAt 调用 configCell 函数?这意味着我需要重做代码并将其放在 cellfORowAt 下?
    • 是的,如果你把 configureCell 函数放在 cellForRowAt 中意味着每次我们调用 tableView.reloadData() 时都会调用 configureCell 函数
    • 它已经存在了,如果我要使用 tableview.reloaddata,我的整个消息将被清除
    • tableView.reloadData() 只是用当前内容重新加载tableView 如何清除数据?
    【解决方案4】:

    似乎这段代码只执行了一次,但你的 UITableView 仍然在加载单元格,因为计数显然是 2。当你将 Message 对象传递给 UICollectionViewCell 方法中的 UICollectionViewCell 类时,您需要在该消息上使用didSet,然后调用您的函数。这意味着每次传入消息时,当它传入时,didSet 中的任何内容都会被执行。

    在你的 UICollectionViewCell 类中:

    var message: Message? {
        didSet {
            configCell(message)
        }
    }
    

    使用你的 UITableViewController 类:

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = // your cell here dequeue cell and downcast as your cell class e.g as! MyCell
    
        cell.message = yourMessagesArray[indexPath.row]
    
        return cell
    }
    

    【讨论】:

      【解决方案5】:

      我遇到了同样的问题,我就是这样解决的。

      在您的 ViewController 中创建一个函数,该函数将动态更新每个单元格

      private func reloadRowAt(_ indexPath: IndexPath) {
          self.tableView.beginUpdates()
          self.tableView.reloadRows( at: [indexPath], with: .fade)
          self.tableView.endUpdates()
      }
      

      现在在 cellForRowAtindexPath() 中使用它 使用它:

      func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
          guard let cell = tableView.dequeueReusableCell(withIdentifier: identifier) as? MyCustomCell else { return UITableViewCell()}
      
         // Download and refresh cell
         let image = imageDownloader.loadImage(from: url) {
             self.reloadRowAt(indexPath) 
         }
         cell.image = image
         return cell
        }
      

      现在查看代码{ self.reloadRowAt(indexPath) },这是下载图像的方法的完成处理程序,一旦下载图像,它就会返回到单元格。

      func loadImage(from url: URL, completion: @escaping () -> Void ) -> UIImage {
          let size = CGSize(width: 100, height: 140)
          // Download and Compress image to fit container size
          DispatchQueue.global(qos: .background).async {
            guard let newimage = self.downloadAndCompress(url: url, newSize: size) else { return }
            // Show in UI
            DispatchQueue.main.async {
              completion()
            }
          }
          return UIImage()
        }
      

      另外我用self.downloadAndCompress的方法将下载的图片压缩成新的大小。

      查看完整代码:

      https://gist.github.com/richimf/fad8d320fbfb5059c5472e0f55ea24c2

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-03-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多