'How to check if IndexPath is valid?

Prior to swift 3, i used to use for example:

let path = self.tableView.indexPathForSelectedRow
if (path != NSNotFound) {
//do something
 }

But now, since i use IndexPath class in swift3, i'm looking for the equivalent for the path != NSNotFound check.

Xcode8.3.1 compiler error: "Binary operator '!=' cannot be applied to operands of type 'IndexPath' and 'Int'"



Solution 1:[1]

To check if IndexPath exists, I use this extension function:

import UIKit

extension UITableView {

    func hasRowAtIndexPath(indexPath: IndexPath) -> Bool {
        return indexPath.section < self.numberOfSections && indexPath.row < self.numberOfRows(inSection: indexPath.section)
    }
}

And to use it I do something like this:

if tableView.hasRowAtIndexPath(indexPath: indexPath) {
    // do something
}

Solution 2:[2]

Semantically, to consider an indexPath invalid, you need something to check for such as a table view or a collection view.

Usually you can consider an indexPath invalid if it represents a row where there is no corresponding data in the data source. (One exception would be "Load more" rows.)

If you really need to create an invalid IndexPath, you can do:

let invalidIndexPath = IndexPath(row: NSNotFound, section: NSNotFound)

After the update:

self.tableView.indexPathForSelectedRow returns an Optional so can be nil if there is no selected row.

if let path = tableView.indexPathForSelectedRow {
  // There is a selected row, so path is not nil.
}
else {
  // No row is selected.
}

Anyway, comparing path against NSNotFound raises an exception in all cases.

Solution 3:[3]

Improving the answer by @pableiros to handle edge case where section or row less than 0. This will happen when the table is empty and you try to access it by listOfSectionHeaders.count - 1, listOfRowsForSection.count - 1

extension UITableView {
    func isValid(indexPath: IndexPath) -> Bool {
        return indexPath.section >= 0 
            && indexPath.section < self.numberOfSections 
            && indexPath.row >= 0 
            && indexPath.row < self.numberOfRows(inSection: indexPath.section)
    }
}

Solution 4:[4]

I stumbled on a case where collectionView(_:didEndDisplaying:forItemAt:) returns an invalid indexPath, so I used indexPath.isEmpty to check whether indexPath was indeed a row/section indexPath.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2
Solution 3
Solution 4 CiNN