RxSwift中的接收和发送可观察的对象

问题描述 投票:1回答:2

我有现有的工作代码,看起来像这样(删除了不必要的内容:]

queryTextField.rx.text.orEmpty
            .throttle(.milliseconds(300), scheduler: MainScheduler.instance)
            .distinctUntilChanged()
            .flatMapLatest { query in
                return try AddFriendViewController.getSearchResults(query)
                    .retry(3)
                    .startWith([])
                    .catchErrorJustReturn([])
            }
            .bind(to: tableView.rx.items(cellIdentifier: "cell", cellType: AddFriendTableViewCell.self)) { (row, item, cell) in                
                cell.nameLabel.text = "\(item.firstName) \(item.lastName)"
            }
            .disposed(by: disposeBag)

当您在文本字段中输入名称时,它会自动(通过API)搜索与该查询匹配的朋友。

但是我还想添加另一个功能-从联系人导入,由其他按钮调用。我有一个本地联系人列表,并使用它们询问API搜索结果。我想在同一位置显示这些结果。但是我不知道如何将这些结果send放入tableView。我想到了要创建一个易变的物品:

var items: Observable<[FriendSearchResult]> = Observable.just([])

但是我不知道如何发送/接收数据。有任何线索吗?

编辑:

感谢@andromedainative,现在的代码看起来像这样:

var items: BehaviorRelay<[FriendSearchResult]> = BehaviorRelay(value: [])

items.asObservable()
        .bind(to: tableView.rx.items(cellIdentifier: "cell", cellType: AddFriendTableViewCell.self)) { (row, item, cell) in                
            cell.nameLabel.text = "\(item.firstName) \(item.lastName)"
        }
        .disposed(by: disposeBag)

queryTextField.rx.text.orEmpty
        .throttle(.milliseconds(300), scheduler: MainScheduler.instance)
        .distinctUntilChanged()
        .flatMapLatest { query in
            return try AddFriendViewController.getSearchResults(query)
                .retry(3)
                .startWith([])
                .catchErrorJustReturn([])
        }
        .bind(to: items) //this was a missing piece
        .disposed(by: disposeBag)

并且从getContacts传递结果很简单:

items.accept(data)

但是,在特殊情况下,我必须刷新数据。如何使用相同的查询调用queryTextField来调用API?

我只发现了一种骇人听闻的方式:

let query = queryTextField.text ?? ""
queryTextField.text = ""
queryTextField.sendActions(for: .valueChanged)
queryTextField.text = query
queryTextField.sendActions(for: .valueChanged)

我必须更改为其他值并将其更改回。还有没有更清洁的解决方案?

ios swift reactive-programming rx-swift
2个回答
0
投票

您可以明确地使用rx将对象绑定到表格视图。我对数组使用BehaviorRelay,因为我希望能够访问项目的.value属性。

这是一个非常伪代码的分析器,因此不会编译,但我希望您能理解其中的要点:

class MyViewController: UITableViewController {

  private let disposeBag = DisposeBag()

  var myItems: BehaviorRelay<[FeedItem]>

  func bindData() {

    tableView.rx.setDelegate(self).disposed(by: disposeBag)

    myItems.asObservable()
        .bind(to: tableView.rx.items) { [weak self] tableView, row, myItemType in
            guard let `self` = self else { return UITableViewCell() }
            let indexPath = IndexPath(row: row, section: 0)
            let myItem = self.myItems.value[indexPath.row]
            let myCell = tableView.dequeueCell(reuseIdentifier: "MyIdentifier", for: indexPath) as! MyCellType

            return myCell
    }.disposed(by: disposeBag)
  }

}

0
投票

[通常,当您要合并两个或多个可观察对象发出的值时,需要使用combineLatestzipwithLatestFrommerge中的一种(可能与scan一起使用)。这取决于您应使用哪种环境。本文可能会有所帮助:Recipes for Combining Observables in RxSwift

以下是针对您的具体情况的想法。下面的代码添加了一些将需要实现的功能:func getContacts() -> Observable<[Contact]>func getSearchResults(_ contact: Contact) -> Observable<[Friend]>

let singleSearchResult = queryTextField.rx.text.orEmpty
    .debounce(.milliseconds(300), scheduler: MainScheduler.instance)
    .distinctUntilChanged()
    .flatMapLatest { query in
        return try getSearchResults(query)
            .retry(3)
            .startWith([])
            .catchErrorJustReturn([])
    }

let contactsSearchResult = checkContactsButton.rx.tap
    .flatMapLatest { getContacts() }
    .flatMapLatest {
        Observable.combineLatest($0.map {
            getSearchResults($0)
                .catchErrorJustReturn([])
        })
        .startWith([])
    }
    .map { $0.flatMap { $0 } }

Observable.merge(singleSearchResult, contactsSearchResult)
    .bind(to: tableView.rx.items(cellIdentifier: "cell", cellType: AddFriendTableViewCell.self)) { (row, item, cell) in
        cell.nameLabel.text = "\(item.firstName) \(item.lastName)"
}
.disposed(by: disposeBag)

顺便说一句,您的getContacts不应该抛出。它的错误应该从Observable发出,而不是抛出。另外,您应该在文本字段上使用反跳功能,而不是限制。后者更适合于Void类型,而不是String。

© www.soinside.com 2019 - 2024. All rights reserved.