Async image set to cell with dynamic height bug

2019-08-20 10:16发布

I'm experiencing bugs with my application when I'm trying to download and set an image async to a cell with dynamic height.

Video of the bug: https://youtu.be/nyfjCmc0_Yk


I'm clueless: can't understand why it happens. I'm saving the cell heights for preventing jumping issues and stuff, I do even update the height of the cell after setting the image.


func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {



            var post : Post
            var cell : PostCell
            post = Posts.shared.post(indexPath: indexPath)

            // I REMOVED SOME NOT IMPORTANT PARTS OF THE CODE 
            // (like setting the text, etc)

            if post.images.count > 0 {
                // Images is attached to the post

                cell.postImageView.sd_setImage(with: URL(string: appSettings.url + "/resources/img/posts/" + post.images[0]), placeholderImage: nil, options: [.avoidAutoSetImage]) { (image, error, type, url) in
                    if let error = error {
                        // placeholder
                        return
                    }

                    DispatchQueue.main.async {
                        let cgRect = image!.contentClippingRect(maxWidth: 300, maxHeight: 400)
                        cell.postImageView.isHidden = false

                        cell.postImageWidthConstraint.constant = cgRect.width
                        cell.postImageViewHeightConstraint.constant = cgRect.height

                        cell.postImageView.image = image

                        cell.layoutIfNeeded()
                        self.cellHeights[indexPath] = cell.frame.size.height

                    }
                }


            } else {
                // No image is attached to the post
                cell.postImageViewHeightConstraint.constant = 0
                cell.postImageWidthConstraint.constant = 0
                cell.postImageView.isHidden = true
            }
            return cell


    }
    var cellHeights: [IndexPath : CGFloat] = [:]
    func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
        cellHeights[indexPath] = cell.frame.size.height

        cell.layoutIfNeeded()

    }
    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        return UITableViewAutomaticDimension
    }
    func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
        if cellHeights[indexPath] != nil {
            return CGFloat(Float(cellHeights[indexPath] ?? 0.0))
        }
        else {
            return UITableViewAutomaticDimension
        }
    }

I've tried calling tableView.beginUpdates() tableView.endUpdates(), it fixes the problem at the beginning, but when scrolling it creates a weird bug :

https://youtu.be/932Kp0p0gfs

(random appearing small part of the image in the tableview)

And when scrolling up, it jumps to the beginning of the post.. maybe due to the incorrect height value?

What do I do wrong?

1条回答
Emotional °昔
2楼-- · 2019-08-20 10:21

You'll surely get such kind of bug if you are to compute the height and the width of the UIImage data and assign those values as the constraint constants of the UIImageView especially in a cell.

Solution for that? Make your datasource/server have a computed width and height and avoid computing it yourself. Meaning in your each Post object, there should be a ready width and height values. That's faster and that solved my issue the same as yours (see this cute personal quick project of mine: https://itunes.apple.com/us/app/catlitter-daily-dose-of-cats/id1366205944?ls=1&mt=8)

Also, I've learned that from some public APIs provided by some established companies like Facebook (each images have its computed sizes ready).

I hope this helps.

查看更多
登录 后发表回答