首页 > 解决方案 > 想在 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)
}

问题---->进行搜索时没有过滤单元格

标签: iosrx-swift

解决方案


函数式反应式编程的本质是在声明时完整地指定值的动态行为。——海因里希·阿弗莫斯

您的视图模型应如下所示:

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。)


推荐阅读