使用 RxSwift 刷新后绑定到 UIRefreshControl
Binding to a UIRefreshControl after refresh using RxSwift
我有一个 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)
}
self.data = Observable.just(notification)
正在创建一个新的 Observable
并在 that Observable
上发送新的 [Notification]
元素,没有人已订阅。
您应该使用 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
移动到更早的位置,而不是在您当前拥有它的下游位置(在 table 视图绑定中)。相反,我认为它应该属于 getNotifications
.
我有一个 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)
}
self.data = Observable.just(notification)
正在创建一个新的 Observable
并在 that Observable
上发送新的 [Notification]
元素,没有人已订阅。
您应该使用 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
移动到更早的位置,而不是在您当前拥有它的下游位置(在 table 视图绑定中)。相反,我认为它应该属于 getNotifications
.