Firebase-更改/删除子项时,在所有表视图中显示重复的表视图行

时间:2018-10-03 17:25:39

标签: swift firebase firebase-realtime-database tableview

我有两个问题,都导致我的应用程序中所有表视图中的行重复:

  1. 在我的表视图中,当我滑动以删除现有值(或行)时,一切正常,并且我的表视图被刷新,并且该行不再存在。但是,当出现新消息(或将其添加到Firebase中的消息下方)时,消息表视图中的每个单元格都会重复。

  2. 此外,当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
    }
}

如果有人知道为什么会发生,那就太好了!

谢谢大家。

1 个答案:

答案 0 :(得分:1)

.observe(.childAdded)方法在第一次调用时实际上会返回节点下的整个对象集,然后在此之后返回新添加的对象。

此外,Firebase DB观察程序与您通过调用命中的普通API调用不同。您在代码中多次调用了“消息”的observe方法。相反,只需调用一次观察者。实现此目的的一种好方法是只在您的didLoad中调用一次观察者。每当您执行更改(例如删除条目)时,它将触发。

也可以在其中执行添加逻辑,然后在didSet中为问题数组重新加载tableview。使整个方法有些反应。

所以重复条目的根本原因是,当您添加对象时,trailingSwipeActionsConfigurationForRowAtdidLoad中的两个观察者都将触发,并且都将附加到同一数组。

也可以对代码进行一些结构化。一旦开始向您的应用程序添加更多功能,它将为您带来真正的帮助。