Reputation: 17
I'm building a screen on my app where profiles will be displayed on a collection view. My data is being retrieved from Firebase and for the first time I'm using Firebase DatabaseUI.
I'm building out a query, then creating a FUICollectionViewDataSource
, dequeuing my cells, and then plugging that dataSource into the collectionView.
The functionality of the dataSource works fine as long as I'm toggling between online and offline users (which checks the value of a child key on the query), but when I change the query to be from male to women, or women to men, (a new query itself) I'm crashing with an NSInternalInconsistenencyException
.
*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Invalid update: invalid number of items in section 0. The number of items contained in an existing section after the update (1) must be equal to the number of items contained in that section before the update (1), plus or minus the number of items inserted or deleted from that section (1 inserted, 0 deleted) and plus or minus the number of items moved into or out of that section (0 moved in, 0 moved out).'
*** First throw call stack: (0x18672d1b8 0x18516455c 0x18672d08c 0x1871e502c 0x18cedc14c 0x18c7b1d4c 0x10020f594 0x1002102c8 0x1001eb3e0 0x101609258 0x101609218 0x10160e280 0x1866da810 0x1866d83fc 0x1866062b8 0x1880ba198 0x18c64d7fc 0x18c648534 0x1000c4200 0x1855e95b8) libc++abi.dylib: terminating with uncaught exception of type NSException
When I'm building out collection views, I'm used to just running commands like this:
collectionView.dataSource = collectionViewDataSource
self.collectionView.reloadData()
But now that calls like above don't work, and I'm not using UICollectionViewDataSource
protocol functions, I'm unsure how to go about creating, running, and displaying new queries which will always have differing number of items per section.
What are the functions that I have to run before processing a new query to not deal with these kinds of crashes?
I've tried deleting all the cells from the collectionView's indexPathsForVisibleItems
, and then reloading data... I've thrown around collectionView.reloadData()
all over the place and still crashes. Not all the time, but the app will definitely crash sooner or later.
How do I go about starting a brand new query on a collectionView and not have to deal with NSInternalInconsistencyExceptions
?
Thanks everyone. I love Firebase and would love to figure this out!
-Reezy
When the VC loads, the getUserData()
function is called.
When the query is changed, the resetQuery()
function is run from a posted notification.
extension BrowseVC {
func getUserData() {
let isOnline = (segmentedControl.selectedSegmentIndex == 0) ? true : false
generateQuery(isOnline: isOnline)
populateDataSource()
}
func resetQuery() {
removeOldData()
getUserData()
}
func removeOldData() {
let indexPaths = collectionView.indexPathsForVisibleItems
collectionView.deleteItems(at: indexPaths)
// collectionView.reloadData()
}
func generateQuery(isOnline: Bool) {
if let selectedShowMe = UserDefaults.sharedInstance.string(forKey: Constants.ProfileKeys.ShowMe) {
let forMen = (selectedShowMe == Constants.ProfileValues.Men) ? true : false
query = FirebaseDB.sharedInstance.buildQuery(forMen: forMen, isOnline: isOnline)
} else {
query = FirebaseDB.sharedInstance.buildQuery(forMen: false, isOnline: isOnline)
}
}
func populateDataSource() {
if let query = query {
collectionViewDataSource = FUICollectionViewDataSource(query: query, view: collectionView, populateCell: { (view, indexPath, snapshot) -> ProfileCVCell in
if let cell = view.dequeueReusableCell(withReuseIdentifier: Constants.CollectionViewCellIdentifiers.ProfileCVCell, for: indexPath) as? ProfileCVCell {
if let userDictionary = snapshot.value as? [String: AnyObject] {
if let user = User(uid: snapshot.key, userDictionary: userDictionary) {
cell.populate(withUser: user)
}
}
return cell
}
return ProfileCVCell()
})
collectionView.dataSource = collectionViewDataSource
collectionView.reloadData()
// collectionView.performBatchUpdates({
// self.collectionView.dataSource = self.collectionViewDataSource
// }, completion: nil)
// collectionView.reloadData()
}
}
}
Upvotes: 0
Views: 724
Reputation: 1217
The reason you're running into this is the FirebaseUI Database data sources assume responsibility for pushing updates to the collection view itself. This way you get animated updates for free and shouldn't ever have to call reloadData.
When you swap out the old data source for a new one, you need to set the data source's collection view to nil
so it stops pushing events to the collection view.
Upvotes: 1