Search code examples
realmrx-swift

Filter realm results with variable id using RxSwift


I want to use Variable in Rxswift to make caseResults search different Results with different boxId, like boxId == 1 get Results and boxId == 2 get another Results

class MainViewModel {

    let cases: Driver<[CaseItemViewModel]>
    let index = Variable<Int>(1)

    init() {
        let caseResults = realm.objects(RMCase.self)
                            .filter("boxId == \(index.value)")
                            .sorted(byKeyPath: "id", ascending: true)


        self.cases = Observable.collection(from: caseResults)
            .asDriverOnErrorJustComplete()
            .map { results in results.map { CaseItemViewModel(with: $0) }}
    }
}


class CaseItemViewModel {
    let cased: RMCase
    let id: Int
    let boxId: Int
    let name: String

    init(with cased: RMCase) {
        self.cased = cased
        self.id = cased.id
        self.boxId = cased.boxId
        self.name = cased.name
    }
}

In the ViewController

    viewModel.boxs
        .drive(tableView.rx.items(cellIdentifier: CellId.main.rawValue, cellType: MainTableViewCell.self)) { [weak self] row, item, cell in
            guard let strongSelf = self else { return }

            cell.setup(with: item)

            // drive collectionView into tableViewCell
            if let collectionView = cell.collectionView {

                strongSelf.viewModel.cases.asObservable()
                    .bind(to:collectionView.rx.items(cellIdentifier: "testcell", cellType: MainCollectionViewCell.self)) { _row, _item, _cell in

                     _cell.setup(with: _item)
                    }
                    .disposed(by: cell.disposeBag)
            }

            }.disposed(by: disposeBag)

Solution

  • First of all, Variable is deprecated, use BehaviorRelay or BehaviorSubject instead.

    Change cases to BehaviorRelay so you don't have to initialise it in init and then observe index property and everytime it changes, bind new result to cases like this:

    let cases = BehaviorRelay<[CaseItemViewModel]>(value: [])
    let index = BehaviorRelay<Int>(value: 1)
    
    init() {
      index
        .flatMap { index -> Observable<Results<RMCase>> in
          let caseResult = realm.objects(RMCase.self)
                                .filter("boxId == \(index)")
                                .sorted(byKeyPath: "id", ascending: true)
    
          return Observable.collection(from: caseResult)
        }
        .map { results in results.map { CaseItemViewModel(with: $0) }}
        .bind(to: cases)
        .disposed(by: disposeBag)
    }
    

    In cases you now always have array of CaseItemViewModel and it will be filled with new values everytime index changes.