Swift UITableView: crash when moving a cell near the footer

Viewed 50

I've implemented a drag-and-drop feature on a sample project, which is a TableView with multiple sections. The interaction works fine, however, when I try to move a single row section cell near its section footer, the app crashes.

example of the interaction that causes the crash

Here is the exception the debugger throws:

Swift/Array.swift:405: Fatal error: Array index is out of range

This is the code I've written so far:

class ViewController: UIViewController {
    
    var data = [["1"],["A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q"]]
    
    let tableView: UITableView = {
        let tableView = UITableView()
        tableView.translatesAutoresizingMaskIntoConstraints = false
        tableView.backgroundColor = .red
        tableView.rowHeight = 55
        tableView.sectionFooterHeight = 50
        return tableView
    }()

    override func viewDidLoad() {
        super.viewDidLoad()
        view.addSubview(tableView)
        NSLayoutConstraint.activate([
            tableView.topAnchor.constraint(equalTo: view.topAnchor),
            tableView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
            tableView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
            tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
        ])
        
        tableView.delegate = self
        tableView.dataSource = self
        tableView.dragDelegate = self
        tableView.dragInteractionEnabled = true
        tableView.register(ShippedProductCell.self, forCellReuseIdentifier: ShippedProductCell.cellID)
    }
    
}

extension ViewController: UITableViewDelegate, UITableViewDataSource, UITableViewDragDelegate {
    
    func numberOfSections(in tableView: UITableView) -> Int {
        return data.count
    }
    
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return data[section].count
    }
    
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: ShippedProductCell.cellID) as! ShippedProductCell
        let shippedProductData = data[indexPath.section][indexPath.row]
        cell.label.text = shippedProductData
        return cell
    }
    
    func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
        return "Section \(section)"
    }
    
    func tableView(_ tableView: UITableView, titleForFooterInSection section: Int) -> String? {
        return "Footer"
    }
    
    func tableView(_ tableView: UITableView, itemsForBeginning session: UIDragSession, at indexPath: IndexPath) -> [UIDragItem] {
        guard indexPath.row != data[indexPath.section].count - 1 else { return [] }
        let dragItem = UIDragItem(itemProvider: NSItemProvider())
        dragItem.localObject = data[indexPath.section][indexPath.row]
        return [ dragItem ]
    }
    
    func tableView(_ tableView: UITableView, moveRowAt sourceIndexPath: IndexPath, to destinationIndexPath: IndexPath) {
        let mover = data[sourceIndexPath.section].remove(at: sourceIndexPath.row)
        data[destinationIndexPath.section].insert(mover, at: destinationIndexPath.row)
        print(data)
    }
        
}

When doing some debugging I found that the destinationIndexPath.row was 1, but the section only has 1 row, which is out of bounds. I would really appreciate your help, thanks.

0 Answers
Related