swift - Firebase - 更改/删除子项时在所有表视图中显示重复的表视图行
问题描述
我有两个问题,这两个问题都导致我的应用程序中的所有表格视图中出现重复的行:
在我的表格视图中,当我滑动以删除现有值(或行)时,一切正常,并且我的表格视图被刷新并且该行不再存在。但是,当出现新消息(或在 Firebase 中的消息下添加)时,消息表视图中的每个单元格都会重复。
此外,当当前用户更改他们的个人资料图片时,一切正常,除了当我进入消息表视图时,消息是否重复?
这是我的代码:
override func viewDidLoad() {
super.viewDidLoad()
table.refreshControl = refresher
DataManager.shared.firstVC = self
self.table.delegate = self
self.table.dataSource = self
let postCell = UINib(nibName: "PostTableViewCell", bundle: nil)
self.table.register(postCell, forCellReuseIdentifier: "cell")
let answerCell = UINib(nibName: "HasAnsweredYourQuestionTableViewCell", bundle: nil)
self.table.register(answerCell, forCellReuseIdentifier: "hasAnsweredCell")
self.questions.removeAll()
Database.database().reference().child("messages").child(Auth.auth().currentUser!.uid)
.observe(.childAdded) { (snap) in
if snap.exists() {
let obj = snap.value as! [String:Any]
print(obj)
let Anonymous = obj["Anonymous"] as! String
print(Anonymous)
let questionID = snap.key
let mess = obj["Message"] as! String
let timestamp = obj["timestamp"] as! Double
let from = obj["From"] as! [String:Any]
let username = from["username"] as? String ?? ""
let photoURL = from["photoURL"] as? String ?? ""
let fromID = from["uid"] as? String ?? ""
Database.database().reference().child("profile").child(fromID).observe(.value, with: { (snapshot) in
let thekey = snapshot.value as? [String:Any]
let verifiedAsker = thekey?["isVerified"] as! String
self.questions.append(Question(questionID: questionID, isAnonymous: Anonymous, message: mess, timestamp: timestamp, fromID: fromID, fromPhoto: photoURL, fromUsername: username, fromVerified: verifiedAsker))
self.questions.sort(by: {$0.createdAt > $1.createdAt})
self.table.reloadData()
})
}
else {
self.table.reloadData()
}
}
Database.database().reference().child("MessageIsAnswered").child(Auth.auth().currentUser!.uid).observe(.childAdded) { (snap) in
let object = snap.key
Database.database().reference().child("posts").child("\(object)").observe(.value) { (snapshot) in
// Get user value
let value = snapshot.value as! [String:Any]
let theAnsweredQuestion = value["Answer"] as? String ?? ""
let IdOfAnswerer = value["ToID"] as? String ?? ""
//let photo_url = value?["photoURL"] as? String ?? ""
let timeStampo = value["timestamp"] as! Double
Database.database().reference().child("profile").child(IdOfAnswerer).observeSingleEvent(of: .value, with: { (snapshot) in
let value = snapshot.value as? NSDictionary
let photo_url = value?["photoURL"] as? String ?? ""
let usernameOfAnswerer = value?["username"] as? String ?? ""
self.answers.append(hasAnswered(answererID: IdOfAnswerer, answeredQuestion: theAnsweredQuestion,answererPhoto : photo_url, answererUsername: usernameOfAnswerer, timestampOfAnswer: timeStampo))
}
}
@IBAction func navigationRightButtonTapped(_ sender: UIButton) {
shareView.isHidden = false
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
var returnValue = 0
switch(mySegmentedControl.selectedSegmentIndex)
{
case 0:
return self.questions.count
break
case 1:
return self.answers.count
break
default:
break
}
return returnValue
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let answeredCell = tableView.dequeueReusableCell(withIdentifier: "hasAnsweredCell", for: indexPath) as! HasAnsweredYourQuestionTableViewCell
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! PostTableViewCell
switch(mySegmentedControl.selectedSegmentIndex)
{
case 0:
cell.selectionStyle = .none
cell.postTextLabel.text = questions[indexPath.row].message
cell.subtitleLabel.text = questions[indexPath.row].createdAt.calenderTimeSinceNow()
if self.questions[indexPath.row].fromVerified == "true"{
cell.isVerifiedImage.image = UIImage(named: "kadabraVerifiedAccount")
}
else {
cell.isVerifiedImage.image = nil
}
if self.questions[indexPath.row].isAnonymous != "true"{
cell.usernameLabel.text = self.questions[indexPath.row].fromUsername
cell.profileImageView.sd_setImage(with: URL(string:self.questions[indexPath.row].fromPhoto), placeholderImage: nil, options: .progressiveDownload, completed: nil)
}
else {
cell.usernameLabel.text = ""
cell.profileImageView.image = nil
cell.isVerifiedImage.image = nil
}
break
case 1:
cell.selectionStyle = .none
cell.profileImageView.sd_setImage(with: URL(string:self.answers[indexPath.row].answererPhoto), placeholderImage: nil, options: .progressiveDownload, completed: nil)
cell.postTextLabel.text = "\(answers[indexPath.row].answererUsername) has answered your question"
cell.subtitleLabel.text = moment(self.answers[indexPath.row].timestampOfAnswer) .fromNow()
cell.usernameLabel.text = ""
cell.isVerifiedImage.image = nil
break
default:
break
}
return cell
return answeredCell
}
@available(iOS 11.0, *)
func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {
let delete = UIContextualAction(style: .destructive, title: "Delete") { (action, view, nil) in
Database.database().reference().child("messages").child(self.currentUserID!).child(self.questions[indexPath.row].questionID).setValue([])
self.questions.removeAll()
Database.database().reference().child("messages").child(Auth.auth().currentUser!.uid)
.observe(.childAdded) { (snap) in
if snap.exists() {
let obj = snap.value as! [String:Any]
print(obj)
let Anonymous = obj["Anonymous"] as! String
print(Anonymous)
let questionID = snap.key
let mess = obj["Message"] as! String
let timestamp = obj["timestamp"] as! Double
let from = obj["From"] as! [String:Any]
let username = from["username"] as? String ?? ""
let photoURL = from["photoURL"] as? String ?? ""
let fromID = from["uid"] as? String ?? ""
Database.database().reference().child("profile").child(fromID).observe(.value, with: { (snapshot) in
let thekey = snapshot.value as? [String:Any]
let verifiedAsker = thekey?["isVerified"] as! String
self.questions.append(Question(questionID: questionID, isAnonymous: Anonymous, message: mess, timestamp: timestamp, fromID: fromID, fromPhoto: photoURL, fromUsername: username, fromVerified: verifiedAsker))
self.questions.sort(by: {$0.createdAt > $1.createdAt})
self.table.reloadData()
})
}
else {
self.table.reloadData()
}
}
}
let report = UIContextualAction(style: .destructive, title: "Report") { (action, view, nil) in
let areUSureAlert = UIAlertController(title: "Are you sure you want to report?", message: "This will block this user from sending you anymore questions, and also report the question to the Kadabra team.", preferredStyle: UIAlertControllerStyle.alert)
areUSureAlert.addAction(UIAlertAction(title: "Ok", style: .default, handler: { (action: UIAlertAction!) in
Database.database().reference().child("messages").child(self.currentUserID!).child(self.questions[indexPath.row].questionID).setValue([])
self.questions.removeAll()
Database.database().reference().child("messages").child(Auth.auth().currentUser!.uid)
.observe(.childAdded) { (snap) in
if snap.exists() {
let obj = snap.value as! [String:Any]
print(obj)
let Anonymous = obj["Anonymous"] as! String
print(Anonymous)
let questionID = snap.key
let mess = obj["Message"] as! String
let timestamp = obj["timestamp"] as! Double
let from = obj["From"] as! [String:Any]
let username = from["username"] as? String ?? ""
let photoURL = from["photoURL"] as? String ?? ""
let fromID = from["uid"] as? String ?? ""
Database.database().reference().child("profile").child(fromID).observe(.value, with: { (snapshot) in
let thekey = snapshot.value as? [String:Any]
let verifiedAsker = thekey?["isVerified"] as! String
self.questions.append(Question(questionID: questionID, isAnonymous: Anonymous, message: mess, timestamp: timestamp, fromID: fromID, fromPhoto: photoURL, fromUsername: username, fromVerified: verifiedAsker))
self.questions.sort(by: {$0.createdAt > $1.createdAt})
self.table.reloadData()
})
}
else {
self.table.reloadData()
}
}
let blockedPost = ["timestamp" : [".sv" : "timestamp"]]
Database.database().reference().child("blocked").child(self.currentUserID!).child(self.questions[indexPath.row].fromID).setValue(blockedPost)
}))
areUSureAlert.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: { (action: UIAlertAction!) in
//dismiss(animated: true, completion: nil)
}))
self.present(areUSureAlert, animated: true, completion: nil)
}
report.backgroundColor = #colorLiteral(red: 0.9529411793, green: 0.8918681279, blue: 0, alpha: 1)
return UISwipeActionsConfiguration(actions: [delete, report])
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
switch(mySegmentedControl.selectedSegmentIndex) {
case 0:
self.performSegue(withIdentifier: "answer", sender: self.questions[indexPath.row])
case 1:
self.performSegue(withIdentifier: "theHasAnswered", sender: self.answers[indexPath.row])
default:
break
}
}
如果有人知道为什么会发生这种情况,那就太好了!
多谢你们。
解决方案
该.observe(.childAdded)
方法实际上是在第一次调用时返回一个节点下的整个对象集,然后再返回新添加的对象。
此外, Firebase DB 观察者不像普通的 API 调用,您可以通过调用它来调用它。您已在代码中多次调用“消息”的观察方法。相反,只调用一次观察者。实现这一点的一个好方法是只调用didLoad
一次观察者。每次您执行更改时都会触发它,例如删除条目。
还在那里执行附加逻辑并在 didSet 中为问题数组重新加载表格视图。使整个方法有点反应。
因此,重复条目的根本原因是,当您添加一个对象时,您的观察者都进入trailingSwipeActionsConfigurationForRowAt
并didLoad
触发,都附加到同一个数组。
还要稍微构造你的代码。一旦您开始向您的应用程序添加更多功能,它将真正帮助您。
推荐阅读
- visual-studio - 如何在 EF Core 中启用运行时脚手架
- linux - 在 cpanel.yml 文件配置中部署的条件路径
- html - 角度拖放问题
- javascript - 需要帮助使用 javascript 为 Next.js 网站过滤 Contentful 上的帖子
- java - ec2实例连接Tomcat服务器失败
- javascript - 为什么这个简单的 JavaScript 程序不起作用?
- python - 如何为正确的名称运行 python 命令(py、python、python3)
- python - 第一层 1D CNN 的最佳输入大小
- r - 在循环函数中应用索引
- powershell - Powershell:扩展存档:无法验证参数“路径”上的参数