How to use RxDataSource with SearchBar?

▼魔方 西西 提交于 2019-12-31 04:07:09

问题


I master RxSwift and when using RxDataSource, the SearchBar delegates do not work for me and he, I can’t see the error. Without RxDataSource everything works, on other screens I have no problems. Tell me, with a fresh look, what is the mistake? why doesn't the filter happen?

private var defaultCategories: [Groups]!
var groupsCoreData = BehaviorRelay<[Groups]>(value: [])

override func viewDidLoad() {
    super.viewDidLoad()
    searchBarRx()
    tableViewRx()
}

let dataSource = RxTableViewSectionedReloadDataSource<SectionModel<String, Groups>>(
    configureCell: { (_, tv, indexPath, element) in
        let cell = tv.dequeueReusableCell(withIdentifier: "addNewWordsToGroup")!
        cell.textLabel?.text = element.title
        return cell
},
    titleForHeaderInSection: { dataSource, sectionIndex in
        return dataSource[sectionIndex].model
}
)

 private func tableViewRx() {
    let dataSource = self.dataSource

    let items = [
        SectionModel(model: "Пример", items: self.defaultCategories
            .filter { $0.titleCategories == "Тест1"}),
        SectionModel(model: "Пример2", items: self.defaultCategories
            .filter { $0.titleCategories == "Тест2" })
        ]

    Observable.just(items)
        .bind(to: tableView.rx.items(dataSource: dataSource))
        .disposed(by: disposeBag)

    tableView
        .rx
        .modelSelected(Groups.self)
        .subscribe(onNext: { [weak self] data in
         }
        .disposed(by: disposeBag)
}

private func searchBarRx() {
    searchBar
        .rx
        .text
        .orEmpty
        .debounce(.microseconds(200), scheduler: MainScheduler.instance)
        .distinctUntilChanged()
        .subscribe { [unowned self] query in
            self.searchBar.showsCancelButton = query.element!.isEmpty
            self.defaultCategories = query.element!.isEmpty ? 
            self.defaultCategories : 
            self.defaultCategories
            .filter({ $0.title?.range(of: query.element!, options: .anchored) != nil
            })
        }
        .disposed(by: disposeBag)
}

query - displays the input characters, but no result. P.S. the arrays are not empty


回答1:


The key is that you don't replace the datasource. Rx is a functional paradigm so no replacement is required. Instead you have to outline your invariants before hand. Like so:


final class ViewController: UIViewController {

    var tableView: UITableView!
    var searchBar: UISearchBar!
    let disposeBag = DisposeBag()

    override func viewDidLoad() {
        super.viewDidLoad()

        let initialItems = [
            SectionModel(model: "Пример", items: [Groups(title: "Group1", titleCategories: "Тест1")]),
            SectionModel(model: "Пример2", items: [Groups(title: "Group2", titleCategories: "Тест2")])
        ]

        let searchTerm = searchBar.rx.text.orEmpty
            .debounce(.microseconds(200), scheduler: MainScheduler.instance)
            .distinctUntilChanged()

        Observable.combineLatest(Observable.just(initialItems), searchTerm)
            .map { filteredSectionModels(sectionModels: $0.0, filter: $0.1) }
            .bind(to: tableView.rx.items(dataSource: dataSource))
            .disposed(by: disposeBag)
    }
}

func filteredSectionModels(sectionModels: [SectionModel<String, Groups>], filter: String) -> [SectionModel<String, Groups>] {
    guard !filter.isEmpty else { return sectionModels }
    return sectionModels.map {
        SectionModel(model: $0.model, items: $0.items.filter { $0.title?.range(of: filter, options: .anchored) != nil
        })
    }
}

private let dataSource = RxTableViewSectionedReloadDataSource<SectionModel<String, Groups>>(
    configureCell: { (_, tv, indexPath, element) in
        let cell = tv.dequeueReusableCell(withIdentifier: "addNewWordsToGroup")!
        cell.textLabel?.text = element.title
        return cell
    },
    titleForHeaderInSection: { dataSource, sectionIndex in
        return dataSource[sectionIndex].model
    }
)

Pay special attention to how I combined the Observable that contains all the items with the Observable that tracks the current search filter. Then I only send the items to the table view that are actually supposed to be displayed.



来源:https://stackoverflow.com/questions/57840328/how-to-use-rxdatasource-with-searchbar

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!