Firebase - отображение дублирующихся строк табличного представления во всех табличных представлениях, когда дочерний элемент изменен / удален - PullRequest
0 голосов
/ 03 октября 2018

У меня есть две проблемы, обе из которых приводят к дублированию строк во всех моих табличных представлениях в моем приложении:

  1. В моем табличном просмотре, когда я провожу пальцем, чтобы удалить существующее значение (или строку), все работает отлично, и мое табличное представление обновляется, и строки больше нет.Но когда появляется новое сообщение (или добавляется в сообщения в Firebase), каждая ячейка в табличном представлении сообщений дублируется.

  2. Кроме того, когда currentuser меняет изображение своего профиля, все работает нормальнокроме случаев, когда я захожу в таблицу сообщений, сообщения дублируются?

Это мой код:

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 голосов
/ 03 октября 2018

Метод .observe(.childAdded) фактически возвращает весь набор объектов в узле, когда он вызывается впервые, а затем возвращает вновь добавленные объекты.

Кроме того, обозреватель БД Firebase не похож нанормальный вызов API, который вы нажимаете , вызывая его.Вы неоднократно вызывали метод наблюдения для «сообщений» в своем коде.Вместо этого, позвоните наблюдателю только один раз.Хороший способ реализовать это - вызвать наблюдателя в вашем didLoad только один раз.Он будет срабатывать каждый раз, когда вы вносите изменения, например, удаляете запись.

Также выполните логику добавления и перезагрузите представление таблицы в didSet для массива вопросов.Делает весь подход немного реактивным.

Таким образом, основная причина ваших дублированных записей в том, что когда вы добавляете объект, оба ваших наблюдателя в trailingSwipeActionsConfigurationForRowAt и didLoad запускаются, оба добавляются к одному и тому жемассив.

Также немного структурируйте ваш код.Это действительно поможет вам, когда вы начнете добавлять больше функций в свое приложение.

...