返回 导航

Swift

hangge.com

Swift - RxSwift的使用详解32(UITableView的使用3:刷新表格数据)

作者:hangge | 2018-03-12 08:10
    很多情况下,表格里的数据不是一开始就准备好的、或者固定不变的。可能我们需要先向服务器请求数据,再将获取到的内容显示在表格中。
    要重新加载表格数据,过去的做法就是调用 tableView reloadData() 方法。本文介绍在使用 RxSwift 的情况下,应该如何刷新数据。

三、数据刷新

1,效果图

(1)界面初始化完毕后,tableView 默认会加载一些随机数据。
(2)点击右上角的刷新按钮,tableView 会重新加载并显示一批新数据。
(3)为方便演示,每次获取数据不是真的去发起网络请求。而是在本地生成后延迟 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()
        
        //创建表格视图
        self.tableView = UITableView(frame: self.view.frame, style:.plain)
        //创建一个重用的单元格
        self.tableView!.register(UITableViewCell.self,
                                 forCellReuseIdentifier: "Cell")
        self.view.addSubview(self.tableView!)
        
        //随机的表格数据
        let randomResult = refreshButton.rx.tap.asObservable()
            .startWith(()) //加这个为了让一开始就能自动请求一次数据
            .flatMapLatest(getRandomResult)
            .share(replay: 1)
        
        //创建数据源
        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
            })
        
        //绑定单元格数据
        randomResult
            .bind(to: tableView.rx.items(dataSource: dataSource))
            .disposed(by: disposeBag)
    }
    
    //获取随机数据
    func getRandomResult() -> Observable<[SectionModel<String, Int>]> {
        print("正在请求数据......")
        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 的作用是当在短时间内(上一个请求还没回来)连续点击多次“刷新”按钮,虽然仍会发起多次请求,但表格只会接收并显示最后一次请求。避免表格出现连续刷新的现象。
//随机的表格数据
let randomResult = refreshButton.rx.tap.asObservable()
    .startWith(()) //加这个为了让一开始就能自动请求一次数据
    .flatMapLatest(getRandomResult)  //连续请求时只取最后一次数据
    .share(replay: 1)

(2)也可以改用 flatMapFirst 来防止表格多次刷新,它与 flatMapLatest 刚好相反,如果连续发起多次请求,表格只会接收并显示第一次请求。 
//随机的表格数据
let randomResult = refreshButton.rx.tap.asObservable()
    .startWith(()) //加这个为了让一开始就能自动请求一次数据
    .flatMapFirst(getRandomResult)  //连续请求时只取第一次数据
    .share(replay: 1)

(3)我们还可以在源头进行限制下。即通过 throttle 设置个阀值(比如 1 秒),如果在1秒内有多次点击则只取最后一次,那么自然也就只发送一次数据请求。
//随机的表格数据
let randomResult = refreshButton.rx.tap.asObservable()
    .throttle(1, scheduler: MainScheduler.instance) //在主线程中操作,1秒内值若多次改变,取最后一次
    .startWith(()) //加这个为了让一开始就能自动请求一次数据
    .flatMapLatest(getRandomResult)
    .share(replay: 1)

附:停止数据请求

    在实际项目中我们可能会需要对一个未完成的网络请求进行中断操作。比如切换页面或者分类时,如果上一次的请求还未完成就要将其取消掉。下面通过样例演示如何实现该功能。

1,效果图

这里我们在前面样例的基础上增加了个“停止”按钮。当发起请求且数据还未返回时(2 秒内),按下该按钮后便会停止对结果的接收处理,即表格不加载显示这次的请求数据。

2,样例代码

该功能简单说就是通过 takeUntil 操作符实现。当 takeUntil 中的 Observable 发送一个值时,便会结束对应的 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()
        
        //创建表格视图
        self.tableView = UITableView(frame: self.view.frame, style:.plain)
        //创建一个重用的单元格
        self.tableView!.register(UITableViewCell.self,
                                 forCellReuseIdentifier: "Cell")
        self.view.addSubview(self.tableView!)
        
        //随机的表格数据
        let randomResult = refreshButton.rx.tap.asObservable()
            .startWith(()) //加这个为了让一开始就能自动请求一次数据
            .flatMapLatest{
                self.getRandomResult().takeUntil(self.cancelButton.rx.tap)
            }
            .share(replay: 1)
        
        //创建数据源
        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
            })
        
        //绑定单元格数据
        randomResult
            .bind(to: tableView.rx.items(dataSource: dataSource))
            .disposed(by: disposeBag)
    }
    
    //获取随机数据
    func getRandomResult() -> Observable<[SectionModel<String, Int>]> {
        print("正在请求数据......")
        let items = (0 ..< 5).map {_ in
            Int(arc4random())
        }
        let observable = Observable.just([SectionModel(model: "S", items: items)])
        return observable.delay(2, scheduler: MainScheduler.instance)
    }
}
评论

全部评论(0)

回到顶部