在 RxSwift 中接收和发送 observable
Posted
技术标签:
【中文标题】在 RxSwift 中接收和发送 observable【英文标题】:Receive and send observable in RxSwift 【发布时间】:2020-01-23 08:17:11 【问题描述】:我有现有的工作代码,看起来像这样(删除了不必要的东西):
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 询问搜索结果。我想在同一个地方显示这些结果。但我不知道如何将这些结果发送到 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?
我只找到了一个 hacky 方法:
let query = queryTextField.text ?? ""
queryTextField.text = ""
queryTextField.sendActions(for: .valueChanged)
queryTextField.text = query
queryTextField.sendActions(for: .valueChanged)
我必须更改为其他值并将其更改回来。有没有更干净的解决方案?
【问题讨论】:
【参考方案1】:您绝对可以使用 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)
【讨论】:
是的,我明白了,但问题是如何连接这两个案例。 这很简单,只需将另一个按钮调用中的项目的值添加到同一个数组中。所以首先你有你添加到数组中的查询结果。 var queriedResults = [SomeItems] 然后你就有了从你的按钮按下得到的项目。 func handleButtonPress() ... let myNewImportedContacts = [SomeItems] myItems.accept(myItems.value + myNewImportedContacts) // 现在你在同一个表视图数据源中 让我换个方式问这个问题。我应该在 flatMapLatest 之后调用什么来将结果传递给项目?【参考方案2】:一般来说,当你想组合两个或多个 observable 发出的值时,你需要使用combineLatest
、zip
、withLatestFrom
或merge
之一(可能与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 发出,而不是抛出。此外,您应该在文本字段上使用 debounce,而不是节流。后者更适合 Void 类型,而不是字符串。
【讨论】:
很好的提示,谢谢。但是,就我而言,我不想合并数据,而是替换它。正如我在编辑的答案中所述,我刚刚使用了接受(您可能想帮助我解决此设置中出现的另一个问题,请参阅我的编辑)。以上是关于在 RxSwift 中接收和发送 observable的主要内容,如果未能解决你的问题,请参考以下文章