TableView inside of a CollectionView cell does not draw on row deletion.

Ok, the setup for this is pretty complex. I'm doing maintenance on an app I did not write. The view structure is as follows:

At the base you have a UICollectionViewController. Each UICollectionViewCell has an assigned UIViewController within it. Each of these controllers is attached to the view hierarchy as a child view controller. The main view of one of these child controllers is a UITableView/UIViewController pair.

Everything seems to be hooked up properly and working well except for one case. Assuming the table-view has more than two rows, If I swipe-left to delete the second row (IndexPath 0,1), the content or row one (IndexPath 0,0) goes blank. I can see the disclosure accessory view but the two UILabels up and disappear. If I tap on the blank row the tap behavior is still intact. If I refresh the table-view, the missing content appears as it should.

To make things a little more interesting, this table-view is implement using RxSwift. Here is the code:

Code Block
private func bind() {
        // Cell for row at index path.
        let curriedArgument: (Int, Assignment, AssessmentTableViewCell) -> Void = { /* rowIndex */_, model, cell in
            cell.assignment = model
        }
        let observer: Observable<[Assignment]>
        // For the widget version of this controller, only display the first N
        // items in a table-view that does not scroll. If more than N items exist
        // the user must tap the `More` view. For the non-widget view, show all
        // available items in a scrolling table-view.
        if isWidget {
            tableView.isScrollEnabled = false
            observer = viewModel
                .assignments
                .asObservable()
                .map({ Array($0.prefix(CPAssignmentWidgetVC.numberOfItemsToDisplay))})
        } else {
            observer = viewModel
                .assignments
                .asObservable()
        }
        observer
            .distinctUntilChanged()
            .bind(to: tableView.rx.items(cellIdentifier: "AssessmentCell"), curriedArgument: curriedArgument)
            .disposed(by: disposeBag)
        // When something changes, update both the widget and the modal view as
        // needed.
        if isWidget {
            Observable
                .combineLatest(viewModel.fetching.asObservable(),
                               viewModel.assignments.asObservable())
                .subscribe(onNext: { [weak self] (isFetching, assignments) in
                    self?.updateFooter(with: assignments, isFetching: isFetching)
                })
                .disposed(by: disposeBag)
        } else {
            viewModel.fetching.asObservable()
                .distinctUntilChanged()
                .debounce(.milliseconds(500), scheduler: MainScheduler.instance)
                .subscribe(onNext: { isFetching in
                    if isFetching {
                        SVProgressHUD.show()
                    } else {
                        SVProgressHUD.dismiss()
                    }
                })
                .disposed(by: disposeBag)
        }
        // Select cell
        tableView
            .rx
            .itemSelected
            .subscribe(onNext: { [unowned self] indexPath in
                self.tableView.deselectRow(at: indexPath, animated: true)
                guard
                    let cell = tableView.cellForRow(at: indexPath) as? AssessmentTableViewCell,
                    let assignment = cell.assignment else { return }
                if cell.assignmentResult != nil {
                    presentOptions(cell)
                } else {
                    guard let patient = patient, patient.hasPermissionToModify(permissionType: .assessments) else {
                        let title = NSLocalizedString("We're sorry!", comment: "Notification error title")
                        let message = NSLocalizedString("You don't have permission to complete this survey", comment: "Notification error message")
                        let dismiss = NSLocalizedString("Dismiss", comment: "Button title")
                        LHDNotification.show(with: title, text: message, type: .error).setDismissButtonTitle(dismiss)
                        return
                    }
                    presentAssignmentEntryForm(assignment)
                }
            })
            .disposed(by: disposeBag)
        // Delete cell (remove associated backing model value)
        tableView
            .rx
            .itemDeleted
            .subscribe(onNext: { indexPath in
                self.viewModel.remove(at: indexPath.row)
            })
            .disposed(by: disposeBag)
        // Display last cell
        tableView
            .rx
            .willDisplayCell
            .subscribe(onNext: { [unowned self] (/* cell */_, indexPath) in
                if indexPath.item + 1 == self.viewModel.numberOfItems {
                    self.viewModel.loadMore()
                }
            })
            .disposed(by: disposeBag)
    }
}


Question: Why is the first row content being wiped out? Assuming no one can know the answer to this I have a follow-up question. How can I get the contents of the entire tableview to redraw themselves after a successful delete? I would have assumed the binding to the table-view on line 27 would handle this automatically when the view-model updates.
Answered by ForumsContributor in
The behaviour may be due to RxSwift, so the question would better be to them.

Did you try just to reload the full table after deletion ?
Code Block
tableView.reload()

Accepted Answer
Yes, I did and I was surprised to find that it had no effect. This made me begin to wonder about my assumptions. For example, what if for some reason, there is no data to display for that cell? In other words, what if the strings are empty. I don't know how this could possibly be the case but I have to verify my assumptions before blaming it on RxSwift. (Time passes) Problem solved! I verified using the .debug() operator that the data being passed to the binding is intact and correct. However, there was an embarrassingly simple bug in the cell logic that prevented the cell, under certain circumstances, from updating itself based on the model. Nothing to see here folks, move along.
Thanks for the feedback.

For others to make use of what you learned, could you detail what was the simple bug in the cell logic ?

And don't forget to close the thread.
TableView inside of a CollectionView cell does not draw on row deletion.
 
 
Q