RxSwiftのVariableをUICollectionViewにbindしつつサイズや余白も適用する

欲張りな子ね。

前準備

・Empty Projectをつくる
・一旦閉じて、ターミナルで該当ディレクトリ開いて pod init
・RxSwift入れてxcworkspace開く
・Main.storyboardにUICollectionViewをブッこんで、ViewControllerとIBOutletで接続

コード

import UIKit
import RxSwift
import RxCocoa

class DataSource: NSObject,
    RxCollectionViewDataSourceType,
    UICollectionViewDataSource,
    UICollectionViewDelegate,
    UICollectionViewDelegateFlowLayout {

    struct Element { let numbers: [Int] }

    var numbers: [Int] = []
    private let disposeBag = DisposeBag()
    private let collectionView: UICollectionView

    init(collectionView: UICollectionView) {
        self.collectionView = collectionView
        super.init()
        self.collectionView.rx.setDelegate(self).disposed(by: disposeBag)
    }

    func collectionView(_ collectionView: UICollectionView, observedEvent: Event<DataSource.Element>) {
        guard case .next(let entity) = observedEvent else { return }
        numbers = entity.numbers
        collectionView.reloadData()
    }

    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        return collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath)
    }

    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return numbers.count
    }

    @objc(collectionView:layout:sizeForItemAtIndexPath:)
    func collectionView(_ collectionView: UICollectionView,
                        layout collectionViewLayout: UICollectionViewLayout,
                        sizeForItemAt indexPath: IndexPath) -> CGSize {
        return CGSize(width: 88, height: 88)
    }

    @objc(collectionView:layout:insetForSectionAtIndex:)
    func collectionView(_ collectionView: UICollectionView,
                        layout collectionViewLayout: UICollectionViewLayout,
                        insetForSectionAt section: Int) -> UIEdgeInsets {
        return UIEdgeInsetsMake(10, 10, 10, 10)
    }
}

class ViewController: UIViewController {
    private let disposeBag = DisposeBag()
    @IBOutlet weak var collectionView: UICollectionView!
    let variable = Variable<[Int]>(Array(0...100))
    var dataSource: DataSource!

    override func viewDidLoad() {
        super.viewDidLoad()

        dataSource = DataSource(collectionView: collectionView)

        variable.asObservable()
            .map { DataSource.Element(numbers: $0) }
            .asDriver(onErrorDriveWith: Driver.empty())
            .drive(collectionView.rx.items(dataSource: dataSource))
            .disposed(by: disposeBag)
    }
}

github.com

↑これが参考になった。

素直にRxDataSourcesでも使えばいいのかもしれないけど、 ほげほげ.drive(collectionView.rx.items(... のやつでViewModelからバインドするにはデリゲートを切る必要があるっぽくて、バインドしつつデリゲートメソッドも生きる方法は今のところこれかなーって感じ。
DataSourceがDelegateを担ってるのアレかもしれないけどどっちもView層だしまあ多少はね?

RxSwiftむずかしい!けどたのしい(^ω^)