Search code examples
swiftuitableviewuikittableviewnsfetchedresultscontroller

UITableView's indexPathsForVisibleRows updates all cells except one


I have a UITableView which populate it cells with a NSFetchedResultsController. Also I use indexPathsForVisibleRows to update visible cells except the one I tapped and edit. But the UI updates all cells with proper calculation except one. If I scroll that tableView then that cell recalculate itself next time it becomes visible.

GIF with the problem: CLICK

There I define the cell to edit and reload Rows for all cells except the one I am editing:

    func textFieldDidChangeSelection(_ textField: UITextField) {
    let tapLocation = textField.convert(textField.bounds.origin, to: tableView)
    guard let indexPath = tableView.indexPathForRow(at: tapLocation) else { return }
    pickedCurrency = fetchedResultsController.object(at: indexPath)
    
    let visibleIndexPath = tableView.indexPathsForVisibleRows ?? []
    var nonActiveIndexPaths = [IndexPath]()
    
    for index in visibleIndexPath where index != indexPath {
        nonActiveIndexPaths.append(index)
    }
    
    tableView.reloadRows(at: nonActiveIndexPaths, with: .none)
}

Why the UI updates all cells except one? Can't find the reason...


Solution

  • Here is how I managed to solve my problem. The thing I understood is I should avoid using tableView.indexPathsForVisibleRows for my case since as @ShawnFrank stated it will reload only visible cells:

    func textFieldDidChangeSelection(_ textField: UITextField) {
    
         //Code for defining an active cell (on which I clicked to edit its textField)
        let tapLocation = textField.convert(textField.bounds.origin, to: tableView)
        guard let pickedCurrencyIndexPath = tableView.indexPathForRow(at: tapLocation) else { return }
        pickedCurrency = fetchedResultsController.object(at: pickedCurrencyIndexPath)
        
        //Array for all IndexPaths which is not selected, i.e. not active
        var nonActiveIndexPaths = [IndexPath]()
        
        //Define all rows tableView has at the moment for particular section 
        //In my case it can be only 1 section which starts at 0 index
        let tableViewRows = tableView.numberOfRows(inSection: 0)
        for i in 0..<tableViewRows {
        //Create indexPath with the rows and section
            let indexPath = IndexPath(row: i, section: 0)
        //Add all IndexPaths to previously created array, except the one that is active now
            if indexPath != pickedCurrencyIndexPath {
                nonActiveIndexPaths.append(indexPath)
            }
        }
        //Reload only rows from the array
        tableView.reloadRows(at: nonActiveIndexPaths, with: .none)
    }