Почему в моем табличном представлении отображаются повторяющиеся ячейки после удаления дочернего элемента? - PullRequest
0 голосов
/ 21 февраля 2019

У меня есть viewcontroller с табличным представлением, и когда пользователь нажимает на ячейку, он переходит к VC2.Когда пользователь выполнил действие (и обновил значения в VC2), я использую self.dismiss(animated: true, completion: nil), чтобы вернуться к контроллеру представления с табличным представлением, однако табличное представление (после того, как пользователь вернулся к табличному представлению) показывает дублированные строки,но дочерний элемент был успешно удален в базе данных Firebase и создан новый дочерний элемент - однако в табличном представлении показаны дочерние элементы, которые не были удалены дважды.

Это весь соответствующий код в VC1:

class PostMessageListViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {

    @IBOutlet weak var table: UITableView!

    var topicID:namePosts?
    let currentUserID = Auth.auth().currentUser?.uid
    var posts = [Post]()

    lazy var refresher: UIRefreshControl = {

        let refreshControl = UIRefreshControl()
        refreshControl.tintColor = .white
        refreshControl.addTarget(self, action: #selector(requestData), for: .valueChanged)

        return refreshControl
    }()
    @objc
    func requestData() {
        self.table.reloadData()
        refresher.endRefreshing()
    }

    func reloadData(){

        table.reloadData()
    }

    override func viewDidLoad() {
        super.viewDidLoad()

        self.table.separatorStyle = UITableViewCellSeparatorStyle.none

        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")

        self.posts.removeAll()
                   Database.database().reference().child("posts").child(postID!.name)
            .observe(.childAdded) { (snap) in

                if snap.exists() {

                    //declare some values here...

                        self.posts.append( //some values here)
                        self.posts.sort(by: {$0.createdAt > $1.createdAt})
                        self.table.reloadData()

                    })
                }
                else {
                    self.table.reloadData()
                }

        }
        //observe if a post is deleted by user
        Database.database().reference().child("posts").child("posts").observe(.childRemoved) { (snapshot) in

            let postToDelete = self.indexOfPosts(snapshot: snapshot)
            self.posts.remove(at: postToDelete)
            self.table.reloadData()
            //self.table.deleteRows(at: [NSIndexPath(row: questionToDelete, section: 1) as IndexPath], with: UITableViewRowAnimation.automatic)

            //self.posts.remove(at: indexPath.row)
        }

    }

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return self.posts.count

    }

    func indexOfPosts(snapshot: DataSnapshot) -> Int {
        var index = 0
        for  post in self.posts {
            if (snapshot.key == post.postID) {
                return index
            }
            index += 1
        }
        return -1
    }

РЕДАКТИРОВАТЬ: Забыл сказать, но я использовал этот код в другом Viewcontroller, и он отлично работаеттам.Однако я просто скопировал свой код из этого в этот и удалил кучу вещей, которые мне не нужны, однако я не могу найти то, что мне не хватает в этом.

1 Ответ

0 голосов
/ 21 февраля 2019

Это не может быть ответ , но это может привести к ответу.Как отмечено в комментариях, для управления источником данных для tableView используются два массива.Один содержит данные, а другой использует технику индексирования - я считаю, что это может привести к проблемам, подобным описанному в вопросе.

Другая проблема заключается в том, что, когда каждый дочерний элемент добавляется изначально, мы повторно сортируеммассив, а затем обновить tableView - это может привести к задержкам и мерцанию.(мерцание = плохо)

Итак, давайте установим пару вещей.Сначала класс, который содержит сообщения

PostClass {
   var post_id = ""
   var post_text = ""
   var creation_date = ""
}

, затем структура Firebase, которая похожа на

posts
   post_id_0
      text: "the first post"
      timestamp: "20190220"
   post_id_1
      text: "the second post"
      timestamp: "20190221"

, а затем небольшая хитрость для заполнения источника данных и оставления дочернего наблюдателя.Это важно, так как вы не хотите обновлять tableView с каждым дочерним элементом, который может (будет) мерцать.Поэтому мы используем, чтобы события childAdded всегда предшествовали событиям .value, чтобы массив заполнялся, а затем .value обновит его один раз, а затем мы будем обновлять tableView каждый раз после.Вот некоторый код - много чего происходит, поэтому пошагово пройдитесь.

var postsArray = [String]()
var initialLoad = true

func ReadPosts() {
    let postsRef = self.ref.child("posts").queryOrdered(byChild: "timestamp")
    postsRef.observe(.childAdded, with: { snapshot in
        let aPost = PostClass()
        aPost.post_id = snapshot.key
        aPost.post_text = snapshot.childSnapshot("text").value as! String
        aPost.creation_date = snapshot.childSnapshot("timestamp").value as! String
        self.postsArray.append(aPost)

        //upon first load, don't reload the tableView until all children are loaded
        if ( self.initialLoad == false ) { 
            self.postsTableView.reloadData()
        }
    })

    //when a child is removed, the event will contain that child snapshot
    //  we locate the child node via it's key within the array and remove it
    //  then reload the tableView
    postsRef.observe(.childRemoved, with: { snapshot in
        let keyToRemove = snapshot.key
        let i = self.postsArray.index(where: { $0.post_id == keyToRemove})
        self.postsArray.remove(at: i)
        self.postsTableView.reloadData()
    })

    //this event will fire *after* all of the child nodes were loaded 
    //  in the .childAdded observer. So children are sorted, added and then
    //  the tableView is refreshed. Set initialLoad to false so the next childAdded
   //   after the initial load will refresh accordingly.
    postsRef.observeSingleEvent(of: .value, with: { snapshot in
        self.postsTableView.reloadData()
        self.initialLoad = false
    })
}

На что обратить внимание

Мы позволяем Firebase выполнять тяжелую работу и упорядочивать узлы с помощью creation_date, чтобы они вошлиorder.

Это будет вызвано, скажем, viewDidLoad, где мы установим initialLoad класс var изначально равным true

...