Search code examples
iosswiftuicollectionviewrx-swiftrxdatasources

RxSwift and UICollectionView, UITableView


I have a question: how to properly implement such a scenario in Rx-way with RxDataSources:

We have a class with UICollectionView (or UITableView, in my case it's collection view), the results are not immediately present, they come asynchronously after some time.

I have implemented my model with sections according to the tutorial here: https://github.com/RxSwiftCommunity/RxDataSources

But the data is created only once with just there:

let sections = [
  SectionOfCustomData(header: "First section", items: [CustomData(anInt: 0, aString: "zero", aCGPoint: CGPoint.zero), CustomData(anInt: 1, aString: "one", aCGPoint: CGPoint(x: 1, y: 1)) ]),
  SectionOfCustomData(header: "Second section", items: [CustomData(anInt: 2, aString: "two", aCGPoint: CGPoint(x: 2, y: 2)), CustomData(anInt: 3, aString: "three", aCGPoint: CGPoint(x: 3, y: 3)) ])
]

Observable.just(sections)
  .bindTo(collectionView.rx.items(dataSource: dataSource))
  .addDisposableTo(disposeBag)

What to do in case my items are available after some time and I want my collection view to be updated automatically?

Thanks for any help.


Solution

  • You can use Variable<[Section]> like this:

    enum Api {
        /// Network response
        static func call() -> Observable<[CustomData]> {
            return .just([CustomData(anInt: 0)])
        }
    }
    
    struct CustomData {
        let anInt: Int
    }
    
    class ViewController: UIViewController {
    
        @IBOutlet weak var tableView: UITableView!
    
        typealias Section = SectionModel<String, CustomData>
        private let sections = Variable<[Section]>([])
        private let dataSource = RxTableViewSectionedReloadDataSource<Section>()
        let disposeBag = DisposeBag()
    
        override func viewDidLoad() {
            super.viewDidLoad()
    
            // change sections by api call
            Api.call()
                .map { (customDatas) -> [Section] in
                    [Section(model: "First section", items: customDatas)]
                }.bindTo(sections)
                .addDisposableTo(disposeBag)
    
            sections.asDriver()
                .drive(tableView.rx.items(dataSource: dataSource))
                .addDisposableTo(disposeBag)
    
        }
    
        @IBAction func removeLastTableViewSection() {
            // or you can change the sections manually.
            sections.value.removeLast()
        }
    }
    

    The UI will update automatically when you change sections.value.

    Hope this may help you.