很多情況下罐孝,表格里的數(shù)據(jù)不是一開始就準(zhǔn)備好的、或者固定不變的肥缔×ぃ可能我們需要先向服務(wù)器請求數(shù)據(jù),再將獲取到的內(nèi)容顯示在表格中。
要重新加載表格數(shù)據(jù)改艇,過去的做法就是調(diào)用tableView
的reloadData()
方法收班。本文介紹在使用RxSwift
的情況下,應(yīng)該如何刷新數(shù)據(jù)谒兄。
三摔桦、數(shù)據(jù)刷新
1,效果圖
(1)界面初始化完畢后承疲,tableView
默認(rèn)會加載一些隨機數(shù)據(jù)邻耕。
(2)點擊右上角的刷新按鈕,tableView
會重新加載并顯示一批新數(shù)據(jù)燕鸽。
(3)為方便演示兄世,每次獲取數(shù)據(jù)不是真的去發(fā)起網(wǎng)絡(luò)請求。而是在本地生成后延遲 2 秒返回绵咱,模擬這種異步請求的情況碘饼。
2,樣例代碼
import UIKit
import RxSwift
import RxCocoa
import RxDataSources
class ViewController: UIViewController {
//刷新按鈕
@IBOutlet weak var refreshButton: UIBarButtonItem!
//表格
var tableView:UITableView!
let disposeBag = DisposeBag()
override func viewDidLoad() {
super.viewDidLoad()
//創(chuàng)建表格視圖
self.tableView = UITableView(frame: self.view.frame, style:.plain)
//創(chuàng)建一個重用的單元格
self.tableView!.register(UITableViewCell.self,
forCellReuseIdentifier: "Cell")
self.view.addSubview(self.tableView!)
//隨機的表格數(shù)據(jù)
let randomResult = refreshButton.rx.tap.asObservable()
.startWith(()) //加這個為了讓一開始就能自動請求一次數(shù)據(jù)
.flatMapLatest(getRandomResult)
.share(replay: 1)
//創(chuàng)建數(shù)據(jù)源
let dataSource = RxTableViewSectionedReloadDataSource
<SectionModel<String, Int>>(configureCell: {
(dataSource, tv, indexPath, element) in
let cell = tv.dequeueReusableCell(withIdentifier: "Cell")!
cell.textLabel?.text = "條目\(indexPath.row):\(element)"
return cell
})
//綁定單元格數(shù)據(jù)
randomResult
.bind(to: tableView.rx.items(dataSource: dataSource))
.disposed(by: disposeBag)
}
//獲取隨機數(shù)據(jù)
func getRandomResult() -> Observable<[SectionModel<String, Int>]> {
print("正在請求數(shù)據(jù)......")
let items = (0 ..< 5).map {_ in
Int(arc4random())
}
let observable = Observable.just([SectionModel(model: "S", items: items)])
return observable.delay(2, scheduler: MainScheduler.instance)
}
}
3悲伶,防止表格多次刷新的說明
(1)flatMapLatest
的作用是當(dāng)在短時間內(nèi)(上一個請求還沒回來)連續(xù)點擊多次“刷新”按鈕艾恼,雖然仍會發(fā)起多次請求,但表格只會接收并顯示最后一次請求麸锉。避免表格出現(xiàn)連續(xù)刷新的現(xiàn)象钠绍。
//隨機的表格數(shù)據(jù)
let randomResult = refreshButton.rx.tap.asObservable()
.startWith(()) //加這個為了讓一開始就能自動請求一次數(shù)據(jù)
.flatMapLatest(getRandomResult)
.share(replay: 1)
(2)我們也對源頭進行限制下。即通過 throttle
設(shè)置個閥值(比如 1 秒)花沉,如果在1秒內(nèi)有多次點擊則只取最后一次柳爽,那么自然也就只發(fā)送一次數(shù)據(jù)請求。
//隨機的表格數(shù)據(jù)
let randomResult = refreshButton.rx.tap.asObservable()
.throttle(1, scheduler: MainScheduler.instance) //在主線程中操作碱屁,1秒內(nèi)值若多次改變磷脯,取最后一次
.startWith(()) //加這個為了讓一開始就能自動請求一次數(shù)據(jù)
.flatMapLatest(getRandomResult)
.share(replay: 1)
附:停止數(shù)據(jù)請求
? ? ? ? 在實際項目中我們可能會需要對一個未完成的網(wǎng)絡(luò)請求進行中斷操作。比如切換頁面或者分類時娩脾,如果上一次的請求還未完成就要將其取消掉赵誓。下面通過樣例演示如何實現(xiàn)該功能。
1柿赊,效果圖
? ? ? ?這里我們在前面樣例的基礎(chǔ)上增加了個“停止”按鈕俩功。當(dāng)發(fā)起請求且數(shù)據(jù)還未返回時(2 秒內(nèi)),按下該按鈕后便會停止對結(jié)果的接收處理碰声,即表格不加載顯示這次的請求數(shù)據(jù)诡蜓。
2,樣例代碼
? ? ? ?該功能簡單說就是通過 takeUntil
操作符實現(xiàn)胰挑。當(dāng) takeUntil
中的 Observable
發(fā)送一個值時蔓罚,便會結(jié)束對應(yīng)的 Observable
椿肩。
import UIKit
import RxSwift
import RxCocoa
import RxDataSources
class ViewController: UIViewController {
//刷新按鈕
@IBOutlet weak var refreshButton: UIBarButtonItem!
//停止按鈕
@IBOutlet weak var cancelButton: UIBarButtonItem!
//表格
var tableView:UITableView!
let disposeBag = DisposeBag()
override func viewDidLoad() {
super.viewDidLoad()
//創(chuàng)建表格視圖
self.tableView = UITableView(frame: self.view.frame, style:.plain)
//創(chuàng)建一個重用的單元格
self.tableView!.register(UITableViewCell.self,
forCellReuseIdentifier: "Cell")
self.view.addSubview(self.tableView!)
//隨機的表格數(shù)據(jù)
let randomResult = refreshButton.rx.tap.asObservable()
.startWith(()) //加這個為了讓一開始就能自動請求一次數(shù)據(jù)
.flatMapLatest{
self.getRandomResult().takeUntil(self.cancelButton.rx.tap)
}
.share(replay: 1)
//創(chuàng)建數(shù)據(jù)源
let dataSource = RxTableViewSectionedReloadDataSource
<SectionModel<String, Int>>(configureCell: {
(dataSource, tv, indexPath, element) in
let cell = tv.dequeueReusableCell(withIdentifier: "Cell")!
cell.textLabel?.text = "條目\(indexPath.row):\(element)"
return cell
})
//綁定單元格數(shù)據(jù)
randomResult
.bind(to: tableView.rx.items(dataSource: dataSource))
.disposed(by: disposeBag)
}
//獲取隨機數(shù)據(jù)
func getRandomResult() -> Observable<[SectionModel<String, Int>]> {
print("正在請求數(shù)據(jù)......")
let items = (0 ..< 5).map {_ in
Int(arc4random())
}
let observable = Observable.just([SectionModel(model: "S", items: items)])
return observable.delay(2, scheduler: MainScheduler.instance)
}
}