Polis Polis - 1 year ago 276
Swift Question

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

So I have the weirdest thing;

I am looping a tableView in order to iterate over all cells. It works fine with less than 5 cells, but crashes with "unexpectedly found nil" for more cells. Here's the code:

for section in 0..<tableView.numberOfSections {
for row in 0..<tableView.numberofRowsInSection(section) {
let indexPath = NSIndexPath(forRow: row, inSection: section)
let cell = tableView?.cellForRowAtIndexPath(indexPath) as? MenuItemTableViewCell

// extract cell properties

The last line is the one that gives the error.

Any thoughts?

Answer Source

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?) {

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 {

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


Hope it helps

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download