Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

tableView.cellForRowAtIndexPath(indexPath) return nil

I got a validation function that loop through my table view, the problem is that it return nil cell at some point.

for var section = 0; section < self.tableView.numberOfSections(); ++section {
    for var row = 0; row < self.tableView.numberOfRowsInSection(section); ++row {
        var indexPath = NSIndexPath(forRow: row, inSection: section)
        if section > 0 {
            let cell = tableView.cellForRowAtIndexPath(indexPath) as! MyCell
            // cell is nil when self.tableView.numberOfRowsInSection(section) return 3 for row 1 and 2
            // ... Other stuff
        }
    }
}

I'm not really sure what I'm doing wrong here, I try double checking the indexPath row and section and they are good, numberOfRowsInSection() return 3 but the row 1 and 2 return a nil cell... I can see my 3 cell in the UI too.

Anybody has an idea of what I'm doing wrong?

My function is called after some tableView.reloadData() and in viewDidLoad, is it possible that the tableview didn't finish reloading before my function is executed event though I didn't call it in a dispatch_async ??

In hope of an answer. Thank in advance

--------------------------- Answer ------------------------

Additional explanation :

cellForRowAtIndexPath only return visible cell, validation should be done in data model. When the cell is constructed in

override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {

It should change itself according to the validation state.

like image 964
Incognito Avatar asked Jul 02 '15 15:07

Incognito


2 Answers

As stated in the documentation, cellForRowAtIndexPath returns:

An object representing a cell of the table, or nil if the cell is not visible or indexPath is out of range.

Hence, unless your table is fully displayed, there are some off screen rows for which that method returns nil.

The reason why it returns nil for non visible cells is because they do not exist - the table reuses the same cells, to minimize memory usage - otherwise tables with a large number of rows would be impossible to manage.

like image 69
Antonio Avatar answered Nov 12 '22 03:11

Antonio


So, to handle that error just do optional binding:

// Do your dataSource changes above

if let cell = tableView.cellForRow(at: indexPath) as? MyTableViewCell {
    // yourCode
}

If the cell is visible your code got applied or otherwise, the desired Cell gets reloaded when getting in the visible part as dequeueReusableCell in the cellForRowAt method.

like image 28
FrugalResolution Avatar answered Nov 12 '22 04:11

FrugalResolution