Reputation: 143
I am new here about RxSwift, In my case, I want to use UserDefaults with RxSwift to simplify my code, so I did this following code
my question is, when I clicked a cell, but the subscribe method submit twice? so what should I do to fix it? thx a lot!
import UIKit
import RxSwift
import RxCocoa
import RxDataSources
class ViewController: UIViewController {
let disposeBag = DisposeBag()
@IBOutlet weak var tableView: UITableView! {
didSet {
tableView.register(UITableViewCell.self, forCellReuseIdentifier: String(describing: UITableViewCell.self))
tableView.rx
.itemSelected
.subscribe { (indexPath) in
UserDefaults.standard.set("\(indexPath)", forKey: "key")
}
.disposed(by: disposeBag)
}
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
UserDefaults.standard.rx
.observe(String.self, "key")
// .debug()
.subscribe(onNext: { (value) in
if let value = value {
print(value)
}
})
.disposed(by: disposeBag)
let dataSource = RxTableViewSectionedReloadDataSource<SectionModel<String, String>>()
dataSource.configureCell = { (dataSource, tableView, indexPath, item) in
let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: UITableViewCell.self), for: indexPath)
cell.textLabel?.text = item
return cell
}
Observable.just([SectionModel(model: "", items: (0..<5).map({ "\($0)" }))])
.bindTo(tableView.rx.items(dataSource: dataSource))
.disposed(by: disposeBag)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
Upvotes: 6
Views: 8057
Reputation: 2094
If you just want to make sure it emits only once in your scenario, use distinctUntilChanged()
as others have suggested. Note that if you tap on the same cell twice, your subscribe
closure will only emit once.
If you want to get a better understanding of why it is emitting twice, I would check if the didSet
on tableView
is called twice. You could try moving this block
tableView.rx
.itemSelected
.subscribe { (indexPath) in
UserDefaults.standard.set("\(indexPath)", forKey: "key")
}
.disposed(by: disposeBag)
to viewDidLoad()
and see if you have the same problem.
Upvotes: 0
Reputation: 31
You can try using take(n) where 'n' is the number of contiguous elements from an observable sequence.
tableView.rx
.itemSelected
.take(1)
.subscribe { (indexPath) in
UserDefaults.standard.set("\(indexPath)", forKey: "key")
}
.disposed(by: disposeBag)
Upvotes: 0
Reputation: 1403
It's indeed some kind of a bug and I would recommed to use distinctUntilChanged()
.
Using debounce()
as suggested by @wisper might work most of the time but is dangerous because you are relying on speed of events emitted by observable.
Upvotes: 6
Reputation: 143
iOS bug, v10.2
UserDefaults.standard.rx
.observe(String.self, "key")
+ .debounce(0.1, scheduler: MainScheduler.asyncInstance)
...
Upvotes: 3