我有现有的工作代码,看起来像这样(删除了不必要的内容:]
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)
我必须更改为其他值并将其更改回。还有没有更清洁的解决方案?
您可以明确地使用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)
}
}
[通常,当您要合并两个或多个可观察对象发出的值时,需要使用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发出,而不是抛出。另外,您应该在文本字段上使用反跳功能,而不是限制。后者更适合于Void类型,而不是String。