0

In my view controller I have a UISearchController associated with the UITableView. So all my normal table view datasource methods do the old

if isSearching {
    // use filteredTableData array
} else {
    // use SharedModel.shared.participants 
}

I'm not clear on how I'd implement that using RxCocoa as I'm brand new to Rx.

Gargoyle
  • 9,590
  • 16
  • 80
  • 145

2 Answers2

1

Create a Variable like below

var tableViewOptions = Variable<[String]>([]) // replace String with your own object

bind tableViewOptions to tableview after your view loads.

tableViewOptions
  .asObservable()
  .bind(to: self.tableView
    .rx
    .items(cellIdentifier: "cellIdentifier",
           cellType: CustomCell.self)) { _, values, cell in
           // do your stuff
}

Then when ever you search change the values of tableViewOptions like below.

if isSearching {
  tableViewOptions.value = filteredTableArray
} else {
  tableViewOptions.value = SharedModel.shared.participants
}
Rugmangathan
  • 3,186
  • 6
  • 33
  • 44
0

I solve this by declaring a decorator for an Observable and an extension for a UISearchBar (you could also declare it for the UISearchController):

//FIXME: Item can't be type constrained. Have to use optional casting.
class FilterableByTitleCollection<Item>: ObservableType {

    private let origin: Observable<Array<Item>>
    private let filteringStrategySource: Observable<TitlableModelFilteringStrategy> //FIXME: This is a strategy source

    init<Origin: ObservableType>(
        origin: Origin,
        filteringStrategySource: Observable<TitlableModelFilteringStrategy>) where Origin.E == Array<Item> {
        self.origin = origin.asObservable()
        self.filteringStrategySource = filteringStrategySource
    }

    typealias E = Array<Item>
    func subscribe<O:ObserverType>(_ observer: O) -> Disposable where O.E == Array<Item> {
        return Observable.combineLatest(
                origin,
                filteringStrategySource
            )
            .observeOn(ConcurrentDispatchQueueScheduler(qos: .userInitiated))
            .map{ origin, strategy in
                guard origin is Array<Titlable> else { assert(false); return origin }
                return origin.filter{ strategy.shouldInclude(item: $0 as! Titlable) }
            }
            .observeOn(MainScheduler.instance)
            .subscribe(observer)
    }

}

...

extension UISearchBar {

    var titlableFilteringStrategy: Observable<TitlableModelFilteringStrategy> {
        return Observable<String?>.merge(
            [
                self.rx.text.asObservable(),
                self.rx.textDidEndEditing
                    .map{ [weak self] in
                        assert(self != nil)
                        return self?.text
                    },
                self.rx.cancelButtonClicked.map{ Optional<String>.some("") }
            ]
        ).distinctUntilChanged{ (old: String?, new: String?) -> Bool in
            old == new
        }.map{ TitlableModelFilteringStrategy(filteringPredicate: $0) }
    }

}

...

struct TitlableModelFilteringStrategy {

    private let filteringPredicate: String
    init(filteringPredicate: String?) {
        self.filteringPredicate = filteringPredicate ?? ""
    }

    func shouldInclude(item: Titlable) -> Bool {
        return filteringPredicate.isEmpty ? true : item.title.localizedCaseInsensitiveContains(filteringPredicate)
    }

    func equals(to another: TitlableModelFilteringStrategy) -> Bool {
        return filteringPredicate == another.filteringPredicate
    }

}

...

protocol Titlable {

    var title: String { get }

}
Timofey Solonin
  • 1,393
  • 13
  • 20