到目前为止,这个想法非常简单,用户搜索与搜索栏文本匹配的电影,这会触发一个请求,用UfuableView填充结果.使用在线发现的教程和示例,我已经设法实现了这一点而没有太多麻烦.
当我试图加载通过滚动表格视图底部触发的下一页结果时,棘手的部分就出现了.
这是到目前为止使用的代码:
public final class Homeviewmodel: NSObject { // MARK: - Properties var searchText: Variable<String> = Variable("") var loadNextPage: Variable<Void> = Variable() lazy var pages: Observable<PaginatedList<Film>> = self.setupPages() // MARK: - Reactive Setup fileprivate func setupPages() -> Observable<PaginatedList<Film>> { return self.searchText .asObservable() .debounce(0.3,scheduler: MainScheduler.instance) .distinctUntilChanged() .flatMapLatest { (query) -> Observable<PaginatedList<Film>> in return TMDbAPI.Films(withTitle: query,atPage: 0) } .shareReplay(1) } }
这是我到目前为止:可观察的页面绑定到HomeViewController中的表视图,其搜索栏文本绑定到searchText.
我正在使用Alamofire在幕后执行API调用,TMDbAPI.Films(withTitle:query)返回一个Observable的分页列表.
这是我的模型结构PaginatedList
public struct PaginatedList<T> { // MARK: - Properties let page: Int let totalResults: Int let totalPages: Int let results: [T] // MARK: - Initializer init(page: Int,totalResults: Int,totalPages: Int,results: [T]) { self.page = page self.totalResults = totalResults self.totalPages = totalPages self.results = results } // MARK: - Helper functions / properties var count: Int { return self.results.count } var nextPage: Int? { let nextPage = self.page + 1 guard nextPage < self.totalPages else { return nil } return nextPage } static func Empty() -> PaginatedList { return PaginatedList(page: 0,totalResults: 0,totalPages: 0,results: []) } } extension PaginatedList { // MARK: - Subscript subscript(index: Int) -> T { return self.results[index] } }
我现在正在寻找一种反应方式来将我的loadNextPage变量挂钩到分页列表的observable,它会触发对下一页的请求.
当搜索栏文本发生变化时,它会将分页重置为0.
我相信需要使用运算符扫描和连接,但我仍然不确定如何…
如何实现这一点的任何建议将非常感谢…
// Some kind of page request result. Modify it to be what you're using. struct SomePageResult { let content: String } // Needs modification to return your actual data func getPage(query: String,number: UInt) -> SomePageResult { return SomePageResult(content: "some content for search (\(query)) on page \(number)") } // Actual implementation let disposeBag = disposeBag() var loadNextPage = PublishSubject<Void>() var searchText = PublishSubject<String>() let currentPage = searchText .distinctUntilChanged() .flatMapLatest { searchText in return loadNextPage.asObservable() .startWith(()) .scan(0) { (pageNumber,_) -> UInt in pageNumber + 1 } .map { pageNumber in (searchText,pageNumber) } } .map { (searchText,pageNumber) in getPage(searchText,number: pageNumber) } currentPage .subscribeNext { print($0) } .adddisposableto(disposeBag) searchText.onNext("zebra") searchText.onNext("helicopter") loadNextPage.onNext() searchText.onNext("unicorn") searchText.onNext("unicorn") searchText.onNext("ant") loadNextPage.onNext() loadNextPage.onNext() loadNextPage.onNext()
输出:
SomePageResult(content: “some content for search (zebra) on page 1”) SomePageResult(content: “some content for search (helicopter) on page 1”) SomePageResult(content: “some content for search (helicopter) on page 2”) SomePageResult(content: “some content for search (unicorn) on page 1”) SomePageResult(content: “some content for search (ant) on page 1”) SomePageResult(content: “some content for search (ant) on page 2”) SomePageResult(content: “some content for search (ant) on page 3”) SomePageResult(content: “some content for search (ant) on page 4”)