用于搜索屏幕的 MVVM 和 RxSwift

Posted

技术标签:

【中文标题】用于搜索屏幕的 MVVM 和 RxSwift【英文标题】:MVVM and RxSwift for Search Screen 【发布时间】:2016-08-24 05:51:14 【问题描述】:

出于教育 MVVM 和 RxSwift 的目的,我想构建一个简单的搜索屏幕,它将有一个表格视图和一个搜索栏。当用户在搜索栏中输入内容时,我将在此表中显示他的内容。听起来很简单,但我找不到适合我的教程。

我已经在视图控制器中编写了所有代码,我只是不明白必须观察搜索文本的变化,然后调用数据库方法,它将通过搜索文本过滤项目。

一些代码,我已经有了。

我的视图控制器

import Foundation
import UIKit
import RxSwift
import RxCocoa

class PlaceSearchViewController: UIViewController 

    //MARK: - 

    @IBOutlet weak var searchBar: UISearchBar!
    @IBOutlet weak var tableView: UITableView!

    //MARK: - Dependencies

    private var viewModel: PlaceSearchViewModel!
    private let disposeBag = DisposeBag()

    //MARK: - Lifecycle

    override func viewDidLoad() 
        super.viewDidLoad()

        viewModel = PlaceSearchViewModel()
        addBindsToViewModel(viewModel)
    

    //MARK: - Rx

    private func addBindsToViewModel(viewModel: PlaceSearchViewModel) 

        searchBar.rx_text.bindTo(viewModel.searchTextObservable)

        viewModel.placesObservable.bindTo(tableView.rx_itemsWithCellFactory) 
            (tableView: UITableView, index, place: Place) in

            let indexPath = NSIndexPath(forItem: index, inSection: 0)
            let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as PlaceCell

            cell.configureWithObject(place)

            return cell

            
            .addDisposableTo(disposeBag)

        tableView.rx_contentOffset
            .subscribe  _ in
                if self.searchBar.isFirstResponder() 
                    _ = self.searchBar.resignFirstResponder()
                
            
            .addDisposableTo(disposeBag)
    

还有我的视图模型:

import Foundation
import RxSwift
import RxCocoa

class PlaceSearchViewModel 

    //MARK: - Dependecies
    private let disposeBag = DisposeBag()

    //MARK: - Model

    private let placesObservable: Observable<[Place]>
    var searchTextObservable = Variable<String>("")

    //MARK: - Set up

    init() 

        placesObservable = searchTextObservable.asObservable()
            //wait 0.3 s after the last value to fire a new value
            .debounce(0.3, scheduler: MainScheduler.instance)
            //only fire if the value is different than the last one
            .distinctUntilChanged()
            //convert Observable<String> to Observable<[Place]>
            .flatMapLatest  searchString -> Observable<[Place]> in

                // some code here which I can't write.

            
            //make sure all subscribers use the same exact subscription
            .shareReplay(1)
    


另外,我有方法 [DataBase searchPlaces:searchText],它返回位置数组 - [Place]。我不明白它在我的 ViewModel 的 flatMapLatest 中的位置和方式。

【问题讨论】:

你检查过 RxSwift 仓库中的RxExample 项目吗? @KhanXc 是的。我现在不想使用他们的 RxDelegates。新框架太多。这就是为什么我想在没有他们的情况下找到解决方案。 一些代表是内置的(除非你使用 RxDatasource)。来自 RxExample 的***图像搜索代码将适合您的目的。它使用驱动程序而不是观察者。 【参考方案1】:

我通过创建 Observable 为我的数据库创建响应式包装器。

这是我的代码

placesObservable = searchTextObservable.asObservable()
            //wait 0.3 s after the last value to fire a new value
            .debounce(0.0, scheduler: MainScheduler.instance)
            //only fire if the value is different than the last one
            .distinctUntilChanged()
            //convert Observable<String> to Observable<Weather>
            .flatMapLatest  searchString -> Observable<[AnyObject]> in
                return TPReactiveDatabase.sharedInstance.searchPlacesByTitle(searchString)
            
            //make sure all subscribers use the same exact subscription
            .shareReplay(1)

以及包装方法searchPlacesByTitle

class TPReactiveDatabase: NSObject 

    static let sharedInstance = TPReactiveDatabase()

    // MARK: - Reactive Place database

    func searchPlacesByTitle(title: String) -> Observable<[AnyObject]> 
        return Observable.create  observer in

            var places = [AnyObject]()

            if (title.characters.count > 0) 
                places = DBAccessKit.searchPlacesByTitle(title)
            

            observer.on(.Next(places))
            observer.on(.Completed)

            return AnonymousDisposable 

            
        
    

【讨论】:

以上是关于用于搜索屏幕的 MVVM 和 RxSwift的主要内容,如果未能解决你的问题,请参考以下文章

如何为MVVM模式链接Retrofit和Repository / ViewModel?

使用 mvvm 搜索 tableview

如何使用MVVM + Swift4实现注册屏幕

页面导航后 WPF MVVM 数据绑定中断

MVVM + WPF - 为具有多个视图的 ViewModel 设计

使用 MVVM 从 WPF 中的 TextBox 进行正确的 DataGrid 搜索