How can I check if an indexPath is valid, thus avoiding an "attempt to scroll to invalid index path" error?

You could check

- numberOfSections
- numberOfItemsInSection: 

of your UICollection​View​Data​Source to see if your indexPath is a valid one.

E.g.

extension UICollectionView {

    func isValid(indexPath: IndexPath) -> Bool {
        guard indexPath.section < numberOfSections,
              indexPath.row < numberOfItems(inSection: indexPath.section)
            else { return false }
        return true
    }

}

A more concise solution?

func indexPathIsValid(indexPath: NSIndexPath) -> Bool {
    if indexPath.section >= numberOfSectionsInCollectionView(collectionView) {
        return false
    }
    if indexPath.row >= collectionView.numberOfItemsInSection(indexPath.section) {
        return false
    }
    return true
}

or more compact, but less readable...

func indexPathIsValid(indexPath: NSIndexPath) -> Bool {
    return indexPath.section < numberOfSectionsInCollectionView(collectionView) && indexPath.row < collectionView.numberOfItemsInSection(indexPath.section)
}

@ABakerSmith's answer is close, but not quite right.

The answer depends on your model.

If you have a multi-section collection view (or table view for that matter - same issue) then it's pretty common to use an array of arrays to save your data.

The outer array contains your sections, and each inner array contains the rows for that section.

So you might have something like this:

struct TableViewData
{
  //Dummy structure, replaced with whatever you might use instead
  var heading: String
  var subHead: String
  var value: Int
}

typealias RowArray: [TableViewData]

typeAlias SectionArray: [RowArray]


var myTableViewData: SectionArray

In that case, when presented with an indexPath, you'd need to interrogate your model object (myTableViewData, in the above example)

The code might look like this:

func indexPathIsValid(theIndexPath: NSIndexPath) -> Bool
{
  let section = theIndexPath.section!
  let row = theIndexPath.row!
  if section > myTableViewData.count-1
  {
    return false
  }
  let aRow = myTableViewData[section]
  return aRow.count < row
}

EDIT:

@ABakerSmith has an interesting twist: Asking the data source. That way you can write a solution that works regardless of the data model. His code is close, but still not quite right. It should really be this:

func indexPathIsValid(indexPath: NSIndexPath) -> Bool 
{
  let section = indexPath.section!
  let row = indexPath.row!

  let lastSectionIndex = 
    numberOfSectionsInCollectionView(collectionView) - 1

  //Make sure the specified section exists
  if section > lastSectionIndex
  {
    return false
  }
  let rowCount = self.collectionView(
    collectionView, numberOfItemsInSection: indexPath.section) - 1

  return row <= rowCount
}