2

Please help me find what is my mistake. I have a table view the data source is an array called items. After one item has been deleted from the items array the cellForRowAt method called and the parameter indexPath.row is equals with items.count. This happens only, when the rows count is just enough to one item is out of the table view's view. When it happens it cause a fatal error (index out of range). A hack is used in this case and the value of the IndexPath.row be decreased.

Please see the following image:

enter image description here

The following code for cellForRowAt:

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
    let cell = tableView.dequeueReusableCell(withIdentifier: "ItemCell", for: indexPath) as! ItemCell

    var i = indexPath.row
    if i >= items.count { i = items.count - 1 } //XXX: hack! Sometimes called with indexPath.row is equal with items.count :(
    cell.set(items[i])

    return cell
}

And the following code for the delete:

    func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath)
{
    if (editingStyle == UITableViewCellEditingStyle.delete)
    {
        items.remove(at: indexPath.row)

        tableView.deleteRows(at: [indexPath], with: UITableViewRowAnimation.fade)
    }
}

I think is not relevant, but I'm using iOS 11.0

UPDATE

I tried, and the following very simple code is also affected:

    class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate
{
    var items = ["0","1","2","3","4","5","6","7","8","9","A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z"]

    override func viewDidLoad()
    {
        super.viewDidLoad()
    }

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
    {
        return items.count
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
    {
        let cell = tableView.dequeueReusableCell(withIdentifier: "ItemCell", for: indexPath)
        cell.textLabel?.text = "\(items[indexPath.row])"

        return cell
    }

    func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath)
    {
        if (editingStyle == UITableViewCellEditingStyle.delete)
        {
            items.remove(at: indexPath.row)
            tableView.deleteRows(at: [indexPath], with: UITableViewRowAnimation.fade)
        }
    }
}

How to reproduce:

  1. Scroll to down to Y be the last item on your screen

enter image description here

  1. Try to delete Y swiping to the left

enter image description here

  1. And getting the following error

enter image description here

enter image description here

Rashwan L
  • 38,237
  • 7
  • 103
  • 107
  • Your "hack" in `cellForRowAt` shouldn't be there. If you actually need it then you have a problem in your `numberOfRowsInSection`. – rmaddy Jun 19 '17 at 16:35
  • My numberOfRowsInSection returning with: return items.count –  Jun 19 '17 at 16:45
  • try reloading your tableVew `tableView.reloadData()` after you delete the row(item as index in `items`) so that numberOfRowsInSection is updated from the new items.count – Jacob Boyd Jun 19 '17 at 16:51
  • I tried before posting but got the same error. :( But thank you! –  Jun 19 '17 at 16:54

1 Answers1

2

Your deletion code looks fine, but you should not do what you´re doing in your cellForRowAt. Do it like this instead:

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "ItemCell", for: indexPath) as! ItemCell
    cell.set(items[indexPath.row])

    return cell
}

And your numberOfRowsInSection should be like this:

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return items.count
}

Update:
We just confirmed that this was a bug related to Xcode 9 beta and iOS 11. Working fine on Xcode 8.x. OP will file a bug to Apple regarding this.

Rashwan L
  • 38,237
  • 7
  • 103
  • 107
  • 1
    My numberOfRowsInSection is same as you mentioned. This is why I don't understand what is the problem. Has no other thread so the items array couldn't be modified by another way. –  Jun 19 '17 at 16:44
  • @EdmundElmer, if you do it as I have in my answer and it´s still not working then you have something else in your code that´s not working. Add more code to the question so that we can continue the investigation. – Rashwan L Jun 19 '17 at 16:50
  • Thank you, I'm going to cut out all the not necessary and not problem-related code and I will post the whole controller code. Thank you again for your help! –  Jun 19 '17 at 16:53
  • I tried with a simple as possible view controller, but I got the same error. :( –  Jun 19 '17 at 17:33
  • @EdmundElmer, just tried out your code and it´s working for me... [Here](https://www.dropbox.com/s/bjojucnt5gkq6vw/SO.zip?dl=0) is my project combined with your code try it out. – Rashwan L Jun 19 '17 at 17:35
  • First of all, thank you for your help! Unfortunately, I got the same error! I'm using iOS 11 on my iPhone 7 and also using iOS 11 on iPhone SE simulator and got the error on both :( Could be something iOS11-related problem? –  Jun 19 '17 at 17:42
  • I tried your code and worked fine (like mine), so it seems to me something iOS11 beta related bug :( –  Jun 19 '17 at 17:49
  • I just tried on Xcode 9 beta, with iOS 11 and my project is working fine. – Rashwan L Jun 19 '17 at 17:49
  • Thank you so-so much for your help! I don't know what is going on here. I'm going investigating what is the problem. Did you try the mentioned element? Because the bug comes, when the last out of view element need to be the last in view element. –  Jun 19 '17 at 17:53
  • @EdmundElmer, you can join me in [this](https://appear.in/stackoverflow) AppearIn video conference and I´ll try to solve your issue there if you need my help I´ll be in there. – Rashwan L Jun 19 '17 at 17:54
  • After i delete cell, my app crash: "Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[__NSArrayM objectAtIndexedSubscript:]: index 4 beyond bounds [0 .. 3]'" But, this just happen sometime when I delete cell from middle, and work fine if I delete from first or last cell. And I can't find any problem. I use ios 11, xcode 9 – Tà Truhoada Apr 10 '18 at 09:48