ios - XCode 中的 tableView 正在返回包含来自数组的随机数据的单元格
问题描述
我正在 xcode 中制作一个简单的消息传递应用程序。表格视图填充有包含右视图和左视图的自定义单元格。当用户收到消息时,左视图被填充,当用户发送消息时,右视图被填充。
问题是在重新加载 tableView 后,有时我会看到单元格中填充了来自包含消息的数组的乱码数据。我不确定发生了什么。
我尝试过的事情:
- 我检查了存储在 Back4App 后端的消息文件,它们都包含正确的 csv 数据
- 我查看了我的细胞计数,它总是准确的
- 我已经在表格重新加载之前和重新加载之后打印了数组和单元格数据,并且数组中的数据都是正确的。
- 如果我留下消息 VC 并返回给它,所有消息都会正确显示,但是当我留在 VC 中并使用发送按钮发送消息时,数据会被打乱一点,并打印出我的 tableView 的奇怪组合
您可以看到底线未正确显示: 显示错误的图像
这是我的聊天VC:
//
// ChatViewController.swift
// Glam
//
// Created by Student on 11/14/20.
// Copyright © 2020 Tucker Weibell. All rights reserved.
//
import UIKit
import Parse
class ChatViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
@IBOutlet weak var tableView: UITableView!
@IBOutlet weak var navTitle: UINavigationItem!
var senders = [String]()
var message = [String]()
var state = [String]()
@IBOutlet weak var textView: UITextView!
@IBOutlet weak var myView: UIView!
@IBOutlet weak var bottomConstraint: NSLayoutConstraint!
var dataStringSender = ""
var dataStringReciever = ""
var senderName = ""
override func viewDidLoad() {
super.viewDidLoad()
getData()
navTitle.title = MessageCustomerViewController.GlobalVars.selectedItem
NotificationCenter.default.addObserver(self, selector: #selector(handleKeyboardNotification), name: UIResponder.keyboardWillShowNotification, object: nil)
let tap = UITapGestureRecognizer(target: self, action: #selector(dismissKeyboard))
self.view.addGestureRecognizer(tap)
}
func getData() {
let user = PFUser.current()
let username = user?.username
senderName = username!
let query = PFUser.query()
query?.whereKey("username", equalTo: username!)
do {
let result = try query?.findObjects()
let file = result![0]["Messages"] as! PFFileObject
do {
let data = try file.getData()
let string = String(decoding: data, as: UTF8.self)
dataStringSender = string
let cvsRows = string.components(separatedBy: "\n")
for row in cvsRows {
var itemsRow = row.components(separatedBy: ",")
print(itemsRow)
itemsRow[2] = itemsRow[2].replacingOccurrences(of: "\r", with: "")
print(itemsRow)
if itemsRow[0] == MessageCustomerViewController.GlobalVars.selectedItem {
senders.append(itemsRow[0])
message.append(itemsRow[1])
state.append(itemsRow[2])
}
}
}
catch {
print(error.localizedDescription)
}
}
catch {
print(error.localizedDescription)
}
loadData()
}
@IBAction func sendMessage(_ sender: Any) {
let query = PFUser.query()
query?.whereKey("username", equalTo: MessageCustomerViewController.GlobalVars.selectedItem)
do {
let result = try query?.findObjects()
if result?[0]["Messages"] != nil {
let file = result![0]["Messages"] as! PFFileObject
do {
let data = try file.getData()
let string = String(decoding: data, as: UTF8.self)
dataStringReciever = string
}
catch {
print(error)
}
}
}
catch {
print(error)
}
dataStringSender = dataStringSender + "\n" + MessageCustomerViewController.GlobalVars.selectedItem + "," + textView.text + "," + "Sent"
dataStringReciever = dataStringReciever + "\n" + senderName + "," + textView.text + "," + "Recieved"
let dataSent = Data(dataStringSender.utf8)
let dataRecieved = Data(dataStringReciever.utf8)
//let fileSent: PFFileObject = PFFileObject(data: dataSent)!
//let fileRecieved: PFFileObject = PFFileObject(data: dataRecieved)!
let fileSent = PFFileObject(name: "message.csv", data: dataSent)
let fileRecieved = PFFileObject(name: "message.csv", data: dataRecieved)
let user = PFUser.current()
user!["Messages"] = fileSent
user?.saveInBackground()
let newQuery = PFUser.query()
newQuery?.whereKey("username", equalTo: MessageCustomerViewController.GlobalVars.selectedItem)
do {
let newResults = try newQuery?.findObjects()
newResults![0]["Messages"] = fileRecieved
newResults![0].saveInBackground()
}
catch {
print(error)
}
clearData()
getData()
print("\n")
print("\n")
print(message)
print("\n")
print("\n")
print(state)
loadData()
}
func loadData() {
self.tableView.reloadData()
}
func clearData() {
message.removeAll()
state.removeAll()
senders.removeAll()
}
@objc func handleKeyboardNotification(notification: NSNotification) {
if let keyboardFrame: NSValue = notification.userInfo![UIResponder.keyboardFrameEndUserInfoKey] as? NSValue {
let keyboardRectangle = keyboardFrame.cgRectValue
var height = keyboardRectangle.height
height = height * -1
bottomConstraint.constant = height + 85
}
}
@objc func dismissKeyboard(sender: UITapGestureRecognizer) {
bottomConstraint.constant = 0
textView.resignFirstResponder()
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return message.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
print([message[indexPath.row]])
let cell = tableView.dequeueReusableCell(withIdentifier: "messagescell") as! MessagesCell
if state[indexPath.row] == "Sent" {
cell.sentText.text = message[indexPath.row]
cell.sentView.backgroundColor = .clear
}
else {
cell.recievedText.text = message[indexPath.row]
cell.recievedView.backgroundColor = .clear
}
return cell
}
}
解决方案
这听起来很像可重复使用的细胞问题。
由于您在此处重用单元格let cell = tableView.dequeueReusableCell(withIdentifier: "messagescell") as! MessagesCell
,因此如果您没有为所有单元格显式设置新值,这些单元格的属性会不时地具有旧状态。
您应该在您的自定义单元实现中覆盖prepareForReuse()
并将您的单元重置为默认值。
推荐阅读
- java - Jackson - 仅序列化 Java Pojo 的列表属性中的对象 ID
- javascript - JS 该功能在本地主机上运行良好,但在实时服务器中却不行
- javascript - WebRTC 的自适应速率控制:分辨率也会改变吗?
- php - MySQL插入不起作用,phpMyAdmin的语法似乎没问题
- c# - GridView 的 PageIndexChanging 事件未触发
- javascript - 如何更改 Puppeteer 日期格式?
- php - 在 MacOS Mojave 10.14.3 上安装 pear
- php - 保持下拉菜单被选中 laravelcollective/html
- php - 如何在没有 Mysql 的情况下使用 php 获取选定的整行数据
- maven - 带有 Spring Boot 的多模块 Web 应用程序 Maven 架构