有时将不正确的图像分配给UITableViewCell中的UIImageView

时间:2018-12-12 15:28:03

标签: ios swift uikit kingfisher

我与数百人进行了群聊,当我快速滚动时,有时用户图像会从某处跳到另一处,或者为用户显示不正确的图像。

我已经关注了一些其他的SO帖子,但是我似乎仍然在做一些错误的事情。有什么突出的地方以及我可以做些什么来解决此问题?

谢谢!

final class MessageCell: UITableViewCell {

    private lazy var profileImageView: UIImageView = {
        let imageView = UIImageView()
        imageView.layer.cornerRadius = 20
        imageView.clipsToBounds = true

        return imageView
    }()

    // MARK: – Init

    override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
        super.init(style: style, reuseIdentifier: reuseIdentifier)

        selectionStyle = .none

        addSubview(profileImageView)

        setupConstraints()
    }

    private func setupConstraints() {
        constrain(profileImageView) {
            let size: CGFloat = 36
            $0.width == size
            $0.height == size
            $0.bottom == $0.superview!.bottom - CGFloat(3)
            $0.left == $0.superview!.left + CGFloat(12)
        }
    }


    func configure(with presentable: CellPresentable) {
        self.presentable = presentable

        if let sender = presentable.sender, presentable.isFirstMessage {
            profileImageView.setImage(url: (sender.object(forKey: "picture") as? PFFile)?.url, fallbackText: presentable.username)
        } else {
            PFUser.query()?.whereKey("objectId", equalTo: presentable.message.senderUserId).getFirstObjectInBackground { [weak self] user, error in
                self?.profileImageView.setImage(url: (user?.object(forKey: "picture") as? PFFile)?.url, fallbackText: presentable.username)
            }
        }
    }

    // MARK: Reuse -

    override func prepareForReuse() {
        super.prepareForReuse()

        profileImageView.kf.cancelDownloadTask()
        profileImageView.image = nil
    }

}

在我的View Controller中:

let cell = tableView.dequeueReusableCell(withIdentifier: "MessageCell") as! MessageCell
let presentable = CellPresentable(for: message, isFirstMessage: isFirstMessage, isLastMessage: isLastMessage)
cell.configure(with: presentable)

return cell

3 个答案:

答案 0 :(得分:0)

您正在处理一个与PFUser.query()的getFirstObjectInBackground异步相关以及系统在该函数的闭包返回之前使单元出队和重用的竞争条件有关的竞争条件。

为了节省内存,系统仅创建有限数量的单元格,并在您的集合视图或表格视图滚动时重新使用它们。然后,它使这些单元出队,并用与其索引路径相关的数据重新配置它们。

调用getFirstObjectInBackground()时,其闭包捕获自我。您的问题是,此时 self 正在被重用。它位于另一个索引路径上,并配置有不同的数据,因此刚刚异步返回给您的映像不再新鲜或不相关。

我的建议是,如果您知道不需要这些图像请求,因为该单元已经滚动到可见状态,并且关闭了容器并进行了完整性检查,以确保该项目仍然符合您的期望,那么该如何取消这些图像请求像这样:

 guard presentable == self?.presentable else {return}
 self?.profileImageView.setImage(url: (user?.object(forKey: "picture") as? PFFile)?.url, fallbackText: presentable.username)  

答案 1 :(得分:0)

在MessageCell的configure函数中尝试以下代码

profileImageView.image = nil

所以新的功能代码:

func configure(with presentable: CellPresentable) {
    self.presentable = presentable
    profileImageView.image = nil
    if let sender = presentable.sender, presentable.isFirstMessage {
        profileImageView.setImage(url: (sender.object(forKey: "picture") as? PFFile)?.url, fallbackText: presentable.username)
    } else {
        PFUser.query()?.whereKey("objectId", equalTo: presentable.message.senderUserId).getFirstObjectInBackground { [weak self] user, error in
            self?.profileImageView.setImage(url: (user?.object(forKey: "picture") as? PFFile)?.url, fallbackText: presentable.username)
        }
    }
}

答案 2 :(得分:0)

这些答案很有帮助,但真正使我感动的是意识到我在完成PFUser.query()之后,并没有将获取的用户存储到任何地方,因此,如果我一次获取了5个用户,则每次获取他们时都会获取它们图像出现。这就是造成延迟的原因。相反,我只是删除了该呼叫,并为这些用户使用了替代方法(因为这些用户不再在我的组中了),并且滚动效果得到了很大改善。