How do I arrange the tableView cells to a different order when the tableView is shown?

Viewed 568

I have set up a tableView using Rx and enabled the user to move the cells up and down using rx.itemMoved:

let testData = BehaviorRelay<[String]>(value: ["hello", "hello again", "hello a third time"])

tableView.isEditing = true

testData.bind(to: tableView.rx.items(cellIdentifier:"cell")) { row, data, cell in
    cell.textLabel?.text = data
}.disposed(by: disposeBag)

tableView.rx.itemMoved
    .subscribe(onNext: { indexPaths in
        //...
    }).disposed(by:disposeBag)

It works, and later I will save the indexPaths to coreData and use that data to set up the tableView cells in the order that the user arranged them in. But that's a problem for later. First, I would like to test to rearrange the cells with some dummy data to see if I can change the cell row order as soon as the tableView is populated. Imagine that this dummy data is coming from coreData.

I have no idea how to do this, but I found something here: https://github.com/ReactiveX/RxSwift/blob/master/Tests/RxCocoaTests/UITableView%2BRxTests.swift that I at least think looks like what I need. I tried it below, but it doesn't do anything:

let testRow = IndexPath(row: 0, section: 0)
let testRow2 = IndexPath(row: 2, section: 0)

tableView.dataSource!.tableView!(tableView, moveRowAt: testRow, to: testRow2)

I also tried

self.tableView.moveRow(at: testRow, to: testRow2)

The logic seems to be what I want to do, but nothing... so how do I do this?

1 Answers

In order to re-order the items, you have to change the order at the source and re-emit the array. This means you have to accept a new array on the Relay. Something like this:

final class ExampleViewController: UITableViewController {

    let disposeBag = DisposeBag()

    override func viewDidLoad() {
        super.viewDidLoad()

        let testData = BehaviorRelay<[String]>(value: ["hello", "hello again", "hello a third time"])

        tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
        tableView.isEditing = true
        tableView.dataSource = nil
        testData.bind(to: tableView.rx.items(cellIdentifier:"cell")) { row, data, cell in
            cell.textLabel?.text = data
        }
        .disposed(by: disposeBag)

        tableView.rx.itemMoved
            .subscribe(onNext: { indexPaths in
                var items = testData.value
                let item = items.remove(at: indexPaths.sourceIndex.row)
                items.insert(item, at: indexPaths.destinationIndex.row)
                testData.accept(items)
            })
            .disposed(by:disposeBag)
    }
}
Related