Cell not showing image after loaded from Firebase Swift

走远了吗. 提交于 2019-12-12 00:50:12

问题


I have a UITableViewCell which shows either an image or text. I have set my UIImageView height and width to <= 150 so that it wouldn't affect the cell height in case the image isn't present but the text is. (this is a messaging app)

Now my problem is, the cell does not show the image after it's loaded and user needs to go back, and view this screen again in order to see the image. How should i solve this?

Before Image is loaded:

After the image is successfully loaded:

as u can see, it doesnt show, only the view was expanded

If user presses on BACK and comes again in this view,

the image now shows.

how should i solve this issue? because I am not able to write tableview.reloaddata() in tableviewcell.

for my code in my tableviewcell to configure my cell:

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 = ""
    }
}

for my loadImageUsingCacheWithUrlString code would be an extension as below:

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

}

回答1:


Your problem clearly after downloading image, your cell is not updated right the time, try self.setNeedDisplays() inside your cell. It tell your cell should update in next view cycle.

Instead of loading and catching yourself, I recommend using KingFisher framework, it do almost everything we need on working with image from remote server: downloading, catching, prefetching ... and show your image immediately after downloading




回答2:


I have tried so many ways, in the end..In my ViewDidload, I just added a delay

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

Delay is required. Without it, it doesn't works. I am assuming it's due to the cell heights were set up and loaded before the image is finished loading, so the tablecell didn't know how much height was needed, that is why we need to reload the tableview after 1 second delay




回答3:


Instead of doing action into the UITableViewCell do action inside cellForRowAt

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

Then you can use tableView.reloadData() inside your UITableViewController

Hope this will help to solve your problem.




回答4:


It seems to be that this code is being executed once but your UITableView is still loading the cell anyway as the count is clearly 2. When you pass in your Message object to your UICollectionViewCell class inside of your cellForRowAt indexPath method, you'll want to use a didSet on that message and THEN call your function. This means that every time a message is passed in and when it is passed in, whatever is inside the didSet will be executed.

Inside your UICollectionViewCell class:

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

Class with your 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:


I had the same issue and this is how I resolved it.

Inside your ViewController create a function that will update each cell dynamically:

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

Now use it inside cellForRowAtindexPath() use it:

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
  }

Now look in the code this { self.reloadRowAt(indexPath) }, this is a completion handler of the method that downloads the image, once the image is downloaded it returns to the cell.

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

In addition, I compressed the downloaded image into a new size with the method self.downloadAndCompress.

See full code:

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



来源:https://stackoverflow.com/questions/50521170/cell-not-showing-image-after-loaded-from-firebase-swift

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!