使用 RxSwift 刷新后绑定到 UIRefreshControl
Posted
技术标签:
【中文标题】使用 RxSwift 刷新后绑定到 UIRefreshControl【英文标题】:Binding to a UIRefreshControl after refresh using RxSwift 【发布时间】:2016-05-30 09:37:08 【问题描述】:我有一个 TableView 的通知。我想使用 UIRefreshControl 拉刷新。如何使用 rx-swift 做到这一点?这是我的代码。为什么我将值设置为变量数据后tableView没有刷新
var refreshControl = UIRefreshControl()
var disposeBag = DisposeBag()
let loadingData = ActivityIndicator()
var data: Observable<[Notification]>!
override func viewDidLoad()
super.viewDidLoad()
self.view = v
v.tableView.registerClass(NotificationsViewCell.self, forCellReuseIdentifier: "Cell")
v.tableView.addSubview(refreshControl)
data = getNotifications()
configureTableDataSource()
configureActivityIndicatorsShow()
refreshControl.rx_controlEvent(.ValueChanged)
.flatMapLatest [unowned self] _ in
return self.getNotifications()
.trackActivity(self.loadingData)
.subscribe(
onNext: notification in
print("success")
self.data = Observable.just(notification) // NOT REFRESH TABLEVIEW
,
onError: error in
print("Error \(error)")
,
onCompleted: () in
print("complete")
,
onDisposed: () in
print("disposed")
)
.addDisposableTo(disposeBag)
func configureTableDataSource()
data
.retry(3)
.doOnError [weak self] error in
self?.v.emptyLabel.hidden = false
self?.v.retryButton.hidden = false
.doOnNext [weak self] result in
if result.count == 0
self?.v.emptyLabel.hidden = false
self?.v.emptyLabel.text = "Tidak ada bisnis favorit"
else
self?.v.emptyLabel.hidden = true
self?.v.retryButton.hidden = true
.trackActivity(loadingData)
.retryWhen _ in
self.v.retryButton.rx_tap
.asDriver(onErrorJustReturn: [])
.map results in
results.map(NotificationsViewModel.init)
.drive(v.tableView.rx_itemsWithCellIdentifier("Cell", cellType: NotificationsViewCell.self)) (index, viewModel, cell) in
cell.viewModel = viewModel
let tap = UITapGestureRecognizer(target: self, action: #selector(self.goToProfile(_:)))
tap.numberOfTapsRequired = 1
cell.photo.tag = index
cell.photo.addGestureRecognizer(tap)
.addDisposableTo(disposeBag)
func configureActivityIndicatorsShow()
loadingData
.driveNext isLoading in
if !isLoading
self.v.indicatorView.stopAnimating()
else
self.v.indicatorView.startAnimating()
self.v.retryButton.hidden = true
self.v.emptyLabel.hidden = true
.addDisposableTo(disposeBag)
loadingData.asObservable()
.bindTo(refreshControl.rx_refreshing)
.addDisposableTo(disposeBag)
func getNotifications() -> Observable<[Notification]>
let parameters = [
"token": NSUserDefaults.standardUserDefaults().objectForKey("token")! as! String
]
return string(.POST, NOTIFICATION_LIST, parameters: parameters)
.map json in
return Notification.parseJSON(JSON.parse(json)["notifications"])
.observeOn(MainScheduler.instance)
编辑::
var data = Variable<[Notification]>([])
override func viewDidLoad()
getNotifications()
.retry(3)
.doOnError [weak self] error in
self?.v.emptyLabel.hidden = false
self?.v.retryButton.hidden = false
.doOnNext [weak self] result in
if result.count == 0
self?.v.emptyLabel.hidden = false
self?.v.emptyLabel.text = "Tidak ada notifikasi"
else
self?.v.emptyLabel.hidden = true
self?.v.retryButton.hidden = true
.trackActivity(loadingData)
.retryWhen _ in
self.v.retryButton.rx_tap
.bindTo(data)
.addDisposableTo(disposeBag)
refreshControl.rx_controlEvent(.ValueChanged)
.flatMapLatest [unowned self] _ in
return self.getNotifications()
.doOnError [weak self] error in
// This not call after the second pull to refresh if No network connection, so refresh control still appear
self?.refreshControl.endRefreshing()
.doOnCompleted [weak self] result in
self?.refreshControl.endRefreshing()
.bindTo(data)
.addDisposableTo(disposeBag)
func configureTableDataSource()
datas.asObservable()
.asDriver(onErrorJustReturn: [])
.map results in
results.map(NotificationsViewModel.init)
.drive(v.tableView.rx_itemsWithCellIdentifier("Cell", cellType: NotificationsViewCell.self)) (index, viewModel, cell) in
cell.viewModel = viewModel
.addDisposableTo(disposeBag)
func configureActivityIndicatorsShow()
loadingData
.driveNext isLoading in
if !isLoading
self.v.indicatorView.stopAnimating()
else
self.v.indicatorView.startAnimating()
self.v.retryButton.hidden = true
self.v.emptyLabel.hidden = true
.addDisposableTo(disposeBag)
【问题讨论】:
【参考方案1】:self.data = Observable.just(notification)
正在创建一个新的Observable
并将新的[Notification]
元素发送到那个 Observable
,没有人订阅。
您应该使用Subject
,例如Variable
。
// instead of `var data: Observable<[Notification]>!`
let data = Variable<[Notification]>([])
// and then later, when you want to send out a new element:
self.data.value = notification
编辑:向您展示如何将它与您已有的东西结合使用。
// this will update `data` upon `refreshControl` value change
refreshControl.rx_controlEvent(.ValueChanged)
.flatMapLatest [unowned self] _ in
return self.getNotifications()
.bindTo(data)
.addDisposableTo(disposeBag)
// this will update `loadingData` when `data` gets a new element
data.asDriver().trackActivity(self.loadingData)
// bind to your table view
data.asDriver().drive(//.....
另外,考虑将retry
和retryWhen
移动得更快,而不是发生在您当前拥有它的下游(在表视图绑定中)。相反,我认为它应该属于getNotifications
。
【讨论】:
你的意思是“让数据=变量([])”?但是如何从这个“data = getNotifications()”中分配数据。我应该更改 getNotifications() 的返回类型吗? 好收获。我还更新了答案,向您展示您可能希望如何重新组织您的代码以符合我的建议。 谢谢,它的工作。我更新了我的代码。但是如果没有连接我有一点问题,然后我拉请求tableView。第一个动作 refreshControl 将隐藏,第二个动作它仍然出现。为什么?以上是关于使用 RxSwift 刷新后绑定到 UIRefreshControl的主要内容,如果未能解决你的问题,请参考以下文章
UITextField 使用 RxSwift 绑定到 ViewModel
使用 RxSwift 将多个 UITextField 绑定到类道具
使用 RxSwift 将 Alamofire 请求绑定到表视图