1

I have simple tableview. . When I want to delete cell from table view, I get that error.

View controller code:

class FoodCategoryDetailTableViewController: UITableViewController {
    var foodCategoryDetailViewModel: FoodCategoryDetailTableViewViewModelType?

    private let disposeBag = DisposeBag()

    override func viewDidLoad() {
        super.viewDidLoad()

        guard let foodCategoryDetailViewModel = foodCategoryDetailViewModel else { return }

        tableView.delegate = nil
        tableView.dataSource = nil

        foodCategoryDetailViewModel.foodsInSelectedCategory
            .bind(to: tableView.rx.items(cellIdentifier: FoodCategoryDetailTableViewCell.cellIdentifier, cellType: FoodCategoryDetailTableViewCell.self))
            { row, food, cell in
                cell.foodCategoryDetailCellViewModel = foodCategoryDetailViewModel.cellViewModel(forRow: row)
            }.disposed(by: disposeBag)

        tableView.rx.itemDeleted.subscribe({ [unowned self] indexPath in
            self.foodCategoryDetailViewModel?.removeFoodFromApplication(atRow: (indexPath.element?.row)!)
            self.tableView.reloadData()
        }).disposed(by: disposeBag)
    }

View Model code:

class FoodCategoryDetailTableViewViewModel: FoodCategoryDetailTableViewViewModelType {
    var foodsInSelectedCategory: BehaviorRelay<[Food]>
    private var foodCategoryId: Int16

    func cellViewModel(forRow row: Int) -> FoodTableViewCellViewModelType? {
        if let food = getFood(atRow: row) {
            return FoodTableViewCellViewModel(foodModel: food)
        }
        return nil
    }

    func removeFoodFromApplication(atRow row: Int) {
        if let food = getFood(atRow: row) {
            var foods = foodsInSelectedCategory.value
            foods.remove(at: row)
            self.foodsInSelectedCategory = BehaviorRelay(value: foods)
            CoreDataHelper.sharedInstance.removeFoodFromApplication(foodName: food.name!)
        }
    }

    private func getFood(atRow row: Int) -> Food? {
        let food = foodsInSelectedCategory.value[row]

        return food
    }

    init(foodCategoryId: Int16) {
        self.foodCategoryId = foodCategoryId
        self.foodsInSelectedCategory = BehaviorRelay(value: CoreDataHelper.sharedInstance.fetchFoodsFromSelectedCategory(foodCategoryId: self.foodCategoryId))
    }
}

I am using Core Data. I get error in function getFood(). It error exist because row in view controller have old count of items in tableview. It is not updating with new count of items (foods) after delete cell.

Tkas
  • 302
  • 3
  • 14
  • Use numberOfRowsInSection = foods.count after all... or better put a tag on your cells, where tag = index of foodsInSelectedCategory ..this way even if you delete a row, the index shall stay there as reference – ares777 Mar 26 '19 at 08:16
  • numberOfRowsInSection is not working =( – Tkas Mar 26 '19 at 08:28
  • 1
    are u using RxDataSource? than `self.tableView.reloadData()` isn't it redundant ?? once u call `self.foodCategoryDetailViewModel?.removeFoodFromApplication(atRow: (indexPath.element?.row)!)` table should be reloaded automotically – Sandeep Bhandari Mar 26 '19 at 08:28
  • no, I am not use RxDataSource – Tkas Mar 26 '19 at 08:29
  • 1
    @tkas: You are setting `tableView.dataSource = nil` how do you expect number of sections and number of rows to get called if u r not using RxDataSource??? – Sandeep Bhandari Mar 26 '19 at 08:31
  • @Sandeep Bhandari thx for your answer, I will try use RxDataSource – Tkas Mar 26 '19 at 08:33
  • 1
    @Tkas: I don't think RxDataSource will help you. I think you have multiple problems here but the sample code doesn't compile so I can't tell for sure. On problem you _absolutely_ have is this line `self.foodsInSelectedCategory = BehaviorRelay(value: CoreDataHelper.sharedInstance.fetchFoodsFromSelectedCategory(foodCategoryId: self.foodCategoryId))`. You should _never_ replace a BehaviorRelay. It will break all of your existing subscriptions. – Daniel T. Mar 26 '19 at 11:02
  • @Daniel T. thank you! How to update my BehaviorRelay (foodsInSelectedCategory) without replacing? – Tkas Mar 26 '19 at 11:22
  • [Answer](https://stackoverflow.com/questions/47452582/how-to-use-behaviorrelay-as-an-alternate-to-variable-in-rxswift) of Ashkan Sarlak helped me. But deleting without animation... – Tkas Mar 26 '19 at 12:35
  • @Tkas: `.accept()` is the correct way as I recall. – Daniel T. Mar 26 '19 at 13:26
  • @Daniel T. I wrote extension with remove function: `public extension BehaviorRelay where Element: RangeReplaceableCollection { public func remove(at index: Element.Index) { var newValue = value newValue.remove(at: index) accept(newValue) } }` – Tkas Mar 26 '19 at 13:30

0 Answers0