I do have following structure:
- TableView
-- Custom Table View Cell
--- CollectionView
---- Custom CollectionView Cell
I want to understand that how can I pass the data from / using view model in this structure with RxSwift - MVVM Structure.
Whenever I do get response from API it should update the data in table view rows and associated collection view cell respectively.
The simplest solution is to use an array of arrays.
For example. Let's assume your API returns:
struct Group: Decodable {
let items: [String]
}
Then your view model would be as simple as this:
func tableViewItems(source: Observable<[Group]>) -> Observable<[[String]]> {
return source
.map { $0.map { $0.items } }
}
When creating your cell, you can wrap the inner array into an observable with Observable.just()
like this:
// in your view controller's viewDidLoad for example.
tableViewItems(source: apiResponse)
.bind(to: tableView.rx.items(cellIdentifier: "Cell", cellType: CollectionTableViewCell.self)) { _, element, cell in
Observable.just(element)
.bind(to: cell.collectionView.rx.items(cellIdentifier: "Cell", cellType: UICollectionViewCell.self)) { _, element, cell in
let label = (cell.viewWithTag(6969) as? UILabel) ?? UILabel()
label.tag = 6969
label.text = element
label.sizeToFit()
cell.addSubview(label)
}
.disposed(by: cell.disposeBag)
}
.disposed(by: dispsoeBag)
Here is an example I wrote just now to demonstrate how you can use RxSwift to do what you want. Important Note: This is a rough example, not optimally written and not tested! I just wrote it using a text editor hope it helps you out, if not I will try to polish it when I have some more time.
class MyViewModel {
// Lets say TableData is your model for the tableView data and CollectionData for your collectionView
public let tableData : PublishSubject<[TableData]> = PublishSubject()
public let collectionData : PublishSubject<[CollectionData]> = PublishSubject()
private let disposeBag = DisposeBag()
func fetchData() {
// Whenever you get an update from your API or whatever source you call .onNext
// Lets assume you received an update and stored them on a variable called newShopsUpdate
self.tableData.onNext(newTableDataUpdate)
self.collectionData.onNext(newCollectionDataDataUpdate)
}
}
class MyViewController: UIViewController {
var tableData: BehaviorRelay<[TableData]> = BehaviorRelay(value: [])
var collectionData: BehaviorRelay<[CollectionData]> = BehaviorRelay(value: [])
let viewModel = MyViewModel()
override func viewDidLoad() {
super.viewDidLoad()
// Setup Rx Bindings
viewModel
.tableData
.observeOn(MainScheduler.instance)
.bind(to: self.tableData)
.disposed(by: DisposeBag())
viewModel
.collectionData
.observeOn(MainScheduler.instance)
.bind(to: self.collectionData)
.disposed(by: DisposeBag())
// Register yours Cells first as usual
// ...
// Setting the datasource using RxSwift
tableData.bind(to: tableView.rx.items(cellIdentifier: "yourCellIdentifier", cellType: costumeTableViewCell.self)) { row, tableData, cell in
// Set all the cell properties here
// Lets also assume you have you collectionView inside one of the cells
cell.tableData = tableData
collectionData.bind(to: cell.collectionView.rx.items(cellIdentifier: "yourCellIdentifier", cellType: costumeCollectionViewCell.self)) { row, collectionData, cell in
// Set all the cell properties here
cell.collectionData = collectionData
}.disposeBag(by: DisposeBag())
}.disposed(by: DisposeBag())
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With