ios - 想在 iOS 中使用 RxSwift 做搜索过滤器
问题描述
我有一个表格视图,其中包含我尝试创建 searchBar 并按书名搜索的书籍列表
这是 HomeViewModel
private var homeModelSubject = PublishSubject<[Book]>()
private var filterModelSubject = PublishSubject<[Book]>()
private var isTableHidden = BehaviorRelay<Bool>(value: false)
var searchValueBehavior = BehaviorRelay<String>(value: "")
var homeModelObservable: Observable<[Book]> {
return homeModelSubject
}
var filterModelObservable: Observable<[Book]> {
return filterModelSubject
}
var isTableHiddenObservable:Observable<Bool> {
return isTableHidden.asObservable()
}
var serchValueObservable: Observable<String> {
return searchValueBehavior.asObservable()
}
init() {
serchValueObservable.subscribe(onNext: { value in
self.homeModelObservable.map({ $0.filter ({
if value.isEmpty {return true}
return ($0.name.lowercased().contains(value.lowercased()))
})
}).bind(to: self.filterModelSubject).disposed(by: self.disposeBag)
}).disposed(by: disposeBag)
}
此函数用于绑定到文本值
func bindToSearchValue() {
searchController.searchBar.rx.text.orEmpty.throttle(.milliseconds(500), scheduler: MainScheduler.instance).distinctUntilChanged()
.bind(to: homeViewModel.searchValueBehavior).disposed(by: disposeBage)
}
这个函数订阅响应
func subscribeToResponse() {
homeViewModel.filterModelObservable.bind(to: self.tableView.rx.items(cellIdentifier: HomeTableViewCell.reuseIdentifier, cellType: HomeTableViewCell.self)) { row,books,cell in
cell.separatorInset = UIEdgeInsets(top: 0, left: 0, bottom: 20, right: UIScreen.main.bounds.width)
cell.titleLabel.text = books.name
cell.secondaryTitleLabel.text = books.type
cell.selectionStyle = .none
if books.available == true {
cell.avalibaleOrNotLabel.text = "Avalibale"
cell.avalibaleOrNotStatus.backgroundColor = .green
} else {
cell.avalibaleOrNotLabel.text = "Not Avalibale"
cell.avalibaleOrNotStatus.backgroundColor = .gray
}
}.disposed(by: disposeBage)
}
问题---->进行搜索时没有过滤单元格
解决方案
函数式反应式编程的本质是在声明时完整地指定值的动态行为。——海因里希·阿弗莫斯
您的视图模型应如下所示:
class HomeViewModel {
let filterModelObservable: Observable<[Book]>
var searchValueObserver: AnyObserver<String?> { searchValueBehavior.asObserver() }
var homeModelObservable: Observable<[Book]> { homeModelSubject }
var isTableHiddenObservable:Observable<Bool> { isTableHidden.asObservable() }
private let homeModelSubject = PublishSubject<[Book]>()
private let isTableHidden = BehaviorRelay<Bool>(value: false)
private let searchValueBehavior = BehaviorSubject<String?>(value: "")
init() {
filterModelObservable = Observable.combineLatest(
searchValueBehavior
.map { $0 ?? "" }
.startWith("")
.throttle(.milliseconds(500), scheduler: MainScheduler.instance),
homeModelSubject
)
.map { searchValue, books in
searchValue.isEmpty ? books : books.filter { $0.name.lowercased().contains(searchValue.lowercased()) }
}
}
}
注意filterModelObservable
将发出的值是如何在创建它的代码中完全指定的。
你不应该需要这么多主题:
受试者提供了一种方便的方式来查看 Rx,但不建议将它们用于日常使用。--介绍 Rx
另请注意,没有 disposeBag。你不应该在你的视图模型中需要一个处理包,否则你可能做错了什么。
您应该尽可能减少视图控制器中包含的逻辑。它应该只包含分配和绑定。所以你bindToSearchBar
应该看起来像这样:
func bindToSearchValue() {
searchController.searchBar.rx.text
.bind(to: homeViewModel.searchValueObserver)
.disposed(by: disposeBage)
}
(您可能还想修正错字disposeBage
。)
推荐阅读
- php - Symfony UniqueEntity 在更新现有实体时显示错误
- angular - 用于打印嵌套值的键值管道
- ruby-on-rails - ActionView::Template::Error - 没有路由匹配 button_to \ link_to 调用控制器动作中的动作
- c# - 一些带有条件的循环。具体问题
- apache-kafka - 是否可以从 nifi 接收数据并将该数据添加到从 kafka 接收的数据中?
- .net-core - 如何将 .net core dll 添加到现有的 .net 框架项目中?
- entity-framework - 如何修复 .Net Core POST 操作中的 400 Bad Request 错误?
- c# - 在 C# 控制台应用程序中,我将如何为二十一点游戏中的纸牌创建“图像”?
- netlogo - Netlogo gis(道路网络):将距离(特征)从 gis 复制到 netlogo 中的道路链接
- c# - 如何将 XML Choice 反序列化为正确的复杂类型