我有两个问题,都导致我的应用程序中所有表视图中的行重复:
在我的表视图中,当我滑动以删除现有值(或行)时,一切正常,并且我的表视图被刷新,并且该行不再存在。但是,当出现新消息(或将其添加到Firebase中的消息下方)时,消息表视图中的每个单元格都会重复。
此外,当currentuser更改其个人资料图片时,一切正常,除非我进入message tableview,消息是否重复?
这是我的代码:
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
}
}
如果有人知道为什么会发生,那就太好了!
谢谢大家。
答案 0 :(得分:1)
.observe(.childAdded)
方法在第一次调用时实际上会返回节点下的整个对象集,然后在此之后返回新添加的对象。
此外,Firebase DB观察程序与您通过调用命中的普通API调用不同。您在代码中多次调用了“消息”的observe方法。相反,只需调用一次观察者。实现此目的的一种好方法是只在您的didLoad
中调用一次观察者。每当您执行更改(例如删除条目)时,它将触发。
也可以在其中执行添加逻辑,然后在didSet中为问题数组重新加载tableview。使整个方法有些反应。
所以重复条目的根本原因是,当您添加对象时,trailingSwipeActionsConfigurationForRowAt
和didLoad
中的两个观察者都将触发,并且都将附加到同一数组。
也可以对代码进行一些结构化。一旦开始向您的应用程序添加更多功能,它将为您带来真正的帮助。