问题
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