Tableview.Cellforrowatindexpath(Indexpath) Return Nil

tableView.cellForRowAtIndexPath(indexPath) return nil

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.

tableView:indexPathForCell returns nil

It could be that the cell is not visible at this moment. tableView:indexPathForCell returns nil in this situation. I solved this using indexPathForRowAtPoint this method works even if the cell is not visible. The code:

UITableViewCell *cell = textField.superview.superview;
NSIndexPath *indexPath = [self.tableView indexPathForRowAtPoint:cell.center];

tableView.cellForRowAtIndexPath returns nil with too many cells (swift)

Because cells are reused, cellForRowAtIndexPath will give you cell only if cell for given indexPath is currently visible. It is indicated by the optional value. If you want to prevent from crash, you should use if let

if let cell = tableView?.cellForRowAtIndexPath(indexPath) as? MenuItemTableViewCell {
// Do something with cell
}

If you want to update values from cell, your cells should update the dataSource items. For example you can create delegate for that

protocol UITableViewCellUpdateDelegate {
func cellDidChangeValue(cell: UITableViewCell)
}

Add delegate to your cell and suppose we have a textField in this cell. We add target for the didCHangeTextFieldValue: for EditingDidChange event so it is called every time the user types somethink in it. And when he do, we call the delegate function.

class MyCell: UITableViewCell {
@IBOutlet var textField: UITextField!

var delegate: UITableViewCellUpdateDelegate?

override func awakeFromNib() {
textField.addTarget(self, action: Selector("didCHangeTextFieldValue:"), forControlEvents: UIControlEvents.EditingChanged)
}

@IBAction func didCHangeTextFieldValue(sender: AnyObject?) {
self.delegate?.cellDidChangeValue(cell)
}
}

Then in cellForRowAtIndexPath you add the delegate

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

let cell = tableView.dequeueReusableCellWithIdentifier("MyCellIdentifier", forIndexPath: indexPath)
cell.delegate = self

return cell
}

And finally we implement the delegate method:

func cellDidChangeValue(cell: UITableViewCell) {

guard let indexPath = self.tableView.indexPathForCell(cell) else {
return
}

/// Update data source - we have cell and its indexPath

}

Hope it helps

indexPathForCell: returning nil

Assuming you are using storyboards and if you are willing to change the approach you are using a possible solution would be (And a cleaner solution in my opinion):

Drag an outlet of your UICollectionView inside your cell into the UITableViewCell. In your storyboard again set the delegate and dataSource of the UICollectionView to your class by dragging the outlet. Of course you will have to use a custom UITableViewCell

In your cellForRowAtIndexPath for the UITableView set the tag of the the UICollectionView to be your indexPath.row. Now in your numberOfItemsInSection you can access the UICollectionView tag property and it will contain the indexPath.row of the UITableViewCell you are trying to access and hence you can access your model.

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

CustomCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cell" forIndexPath:indexPath];

// do stuff to setup the cell
// now reload the collection view that it contains
cell.collectionView.tag = indexPath.row;
[cell.collectionView reloadData];
return cell;
}

- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {

// get my model from the index path and return the count of an array it contains
Model *model = dataArray[collectionView.tag];

return model.count;

}


Related Topics



Leave a reply



Submit