0

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

我已经关注了其他一些 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
    }

}

在我的视图控制器中:

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

return cell
4

3 回答 3

0

您正在处理与 PFUser.query() 的 getFirstObjectInBackground 异步相关的竞争条件,并且您的单元格在该函数的闭包返回之前被系统出列和重用。

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

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

我的建议是弄清楚如何取消这些图像请求,如果你知道你不需要它们,因为单元格已经滚动过去可见并且在封闭内进行完整性检查,以确保该项目仍然是你期望的那样:

 guard presentable == self?.presentable else {return}
 self?.profileImageView.setImage(url: (user?.object(forKey: "picture") as? PFFile)?.url, fallbackText: presentable.username)  
于 2018-12-12T15:36:55.277 回答
0

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

于 2018-12-12T16:10:52.310 回答
0

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

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)
        }
    }
}
于 2018-12-12T15:38:28.307 回答