Reputation: 2295
I started using RxSwift
in my iOS project and I have a UITableView
with a custom UITableViewCell
subclass. Within that subclass, I have a UICollectionView
.
Populating the tableview
using RxSwift
works pretty flawlessly, I'm using another extension of RxSwift
for that (RxDataSources)
Here's how I'm doing it:
self.dataSource = RxTableViewSectionedReloadDataSource<Section>(configureCell: {(section, tableView, indexPath, data) in
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! TableViewCellWithCollectionView
switch indexPath.section {
case 0:
cell.collectionViewCellNibName = "ContactDataItemCollectionViewCell"
cell.collectionViewCellReuseIdentifier = "contactDataItemCellIdentifier"
case 1, 2:
cell.collectionViewCellNibName = "DebtCollectionViewCell"
cell.collectionViewCellReuseIdentifier = "debtCellIdentifier"
default:
break
}
cell.registerNibs(indexPath.section, nativePaging: false, layoutDirection: indexPath.section != 0 ? .horizontal : .vertical)
let cellCollectionView = cell.collectionView!
data.debts.asObservable().bind(to: cellCollectionView.rx.items(cellIdentifier: "debtCellIdentifier", cellType: DebtCollectionViewCell.self)) { row, data, cell in
cell.setup(debt: data)
}
return cell
})
This actually works. But the problem arises when a tableview
cell gets scrolled off the screen and reappears. This triggers the code block from above and lets the app crash when
data.debts.asObservable().bind(to: cellCollectionView.rx.items(cellIdentifier: "debtCellIdentifier", cellType: DebtCollectionViewCell.self)) { row, data, cell in
cell.setup(debt: data)
}
is invoked twice on the same tableview cell (The funny thing is, even Xcode crashes without any trace).
What can I do to avoid this?
EDIT:
I have found a solution, but I must admit that I'm not really happy with it... Here's the idea (tested and works)
I define another Dictionary
in my class:
var boundIndizes = [Int: Bool]()
and then I make an if
around the binding like this:
if let bound = self.boundIndizes[indexPath.section], bound == true {
//Do nothing, content is already bound
} else {
data.debts.asObservable().bind(to: cellCollectionView.rx.items(cellIdentifier: "debtCellIdentifier", cellType: DebtCollectionViewCell.self)) { row, data, cell in
cell.setup(debt: data)
}.disposed(by: self.disposeBag)
self.boundIndizes[indexPath.section] = true
}
But I cannot believe there is no "cleaner" solution
Upvotes: 2
Views: 2399
Reputation: 1403
The issue is you are binding your data.debts
to the collectionView within the cell every time the cell is dequeued.
I would recommend you move the logic that is related to your data.debts
to the cell itself and declare a var disposeBag: DisposeBag
which you reinstantiate on prepareForReuse
. See this answer for reference.
Upvotes: 1