Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Catching a UICollectionView perform batch updates assertion failure in Swift?

I'm using UICollectionView's performBatchUpdates(_:completion:) method. The problem is that sometimes my complex diff logic fails and returns an incorrect number of sections to insert. This causes a mismatch between the number of items I insert and the number reported from the data source. Whenever that happens, we get the following error:

Assertion failure in -[CollectionView _endItemAnimationsWithInvalidationContext:tentativelyForReordering:animator:]

Error when performing batch updates: Invalid update: invalid number of sections. The number of sections contained in the collection view after the update (25) must be equal to the number of sections contained in the collection view before the update (19), plus or minus the number of sections inserted or deleted (0 inserted, 0 deleted).

I realize that the correct solution is to fix my diffing logic such that there is no mis-match between the number of items returned and the number of insertions I call.

However, what I want to do is make it so that even if my logic fails in the future, rather than clashing the app, it will simply reload the collection view's data.

How can I do this in Swift?

like image 750
Senseful Avatar asked Mar 07 '17 00:03

Senseful


1 Answers

NSExceptions cannot be caught in Swift by default, so create a bridge similar to this one, or this one.

Even if you catch the assertion failure, the user cannot interact with the collection view, so you'll need to recreate the collection view.

TryCatch.try({
  collectionView.performBatchUpdates({
    collectionView.insertItems(at: indexPaths)
    collectionView.insertSections(sections)
  }, completion: nil)
}, catch: { exception in
  print("Error updating collection view: \(exception)")

  collectionView.removeFromSuperview()

  // recreate the collection view (make sure to set datasource and delegates)
  collectionView = ...
  collectionView.dataSource = ...
  collectionView.delegate = ...
}, finally: nil)
like image 175
Senseful Avatar answered Oct 13 '22 23:10

Senseful