FirebaseTableViewDataSource crashes on user signou

2019-07-18 21:42发布

My app has a UITableViewController which uses a FirebaseTableViewDataSource (from FirebaseUI). The table shows the user's bookmarked posts correctly, but when I log that user off, and log another user in, the app crashes with the following message:

* Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Invalid update: invalid number of rows in section 0. The number of rows contained in an existing section after the update (1) must be equal to the number of rows contained in that section before the update (2), plus or minus the number of rows inserted or deleted from that section (1 inserted, 0 deleted) and plus or minus the number of rows moved into or out of that section (0 moved in, 0 moved out).'*

I suspect the problem is related to how FirebaseUI updates the content of the tableView. I've being debugging this for the past 4 days; searched the SO questions; read the relevant docs but none mentions this unique issue. Any help will be much appreciated.

The Details (Sorry it's actually long)

This is my database structure:

|
+-posts
|   |
|   +-$postid
|        |
|        +-/* properties of a post: title, text, etc */
|
+-users
   |
   +-$userid
        |
        +-bookmarks
             |
             +-post1: true
             |
             +-post2: true

I am using FirebaseUI to show a user his/her bookmarks by passing the users/$userid/bookmarks ref to FirebaseTableViewDataSource as a query. Then for each key, I observe a single value event on posts/$postid in order to retrieve the post details...code below:

self.authStateListenerHandle = FIRAuth.auth()?.addStateDidChangeListener { auth, user in

    guard let user = user else {
        return
    }

    self.query = FIRDatabase.database().reference().child("users").child(user.uid).child("bookmarks")

    self.tableViewDataSource = FirebaseTableViewDataSource(query: self.query!, view: self.tableView, populateCell: { (tableView, indexPath, snapshot) -> UITableViewCell in

        if snapshot.exists() {

            let postRef = FIRDatabase.database().reference().child("posts").child(snapshot.key)

            let cell = tableView.dequeueReusableCell(withIdentifier: BookmarksVC.reuseIdentifier, for: indexPath) as! MiniTableCell

            postRef.observeSingleEvent(of: .value, with: { (snapshot) in
                if snapshot.exists() {
                    let post = Event(snapshot: snapshot)!
                    let postVM = EventViewModel(post: post)
                    cell.populateCellWithEvent(postVM)
                    cell.delegate = self
                }
            })

            return cell
        }
        else {
            return UITableViewCell()
        }
    })

    self.tableView.dataSource = self.tableViewDataSource
}

I put the above code in viewDidAppear and then remove the authStateListenerHandle in viewWillDisappear like so

override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(animated)
    if let handle = self.authStateListenerHandle {
        FIRAuth.auth()?.removeStateDidChangeListener(handle)
    }
}

Almost everything works fine except, when I am viewing the bookmarks for a user, then log out and log back in, the app crashes with the message

* Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Invalid update: invalid number of rows in section 0. The number of rows contained in an existing section after the update (1) must be equal to the number of rows contained in that section before the update (2), plus or minus the number of rows inserted or deleted from that section (1 inserted, 0 deleted) and plus or minus the number of rows moved into or out of that section (0 moved in, 0 moved out).' *

1条回答
放我归山
2楼-- · 2019-07-18 21:58

In the viewWillDisappear set the self.tableViewDataSource = nil. So, that you don't update the dataSource improperly.

查看更多
登录 后发表回答