RxSwift + UserDefaults
Asked Answered
F

4

6

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.
    }
}
Florist answered 18/3, 2017 at 17:22 Comment(0)
C
6

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.

Cease answered 31/10, 2017 at 10:58 Comment(1)
Only one l in distinctUntilChanged()Galloot
F
3

iOS bug, v10.2

UserDefaults.standard.rx
    .observe(String.self, "key")
+   .debounce(0.1, scheduler: MainScheduler.asyncInstance)
    ...
Florist answered 19/3, 2017 at 11:1 Comment(0)
K
0

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)
Kilt answered 10/4, 2019 at 7:26 Comment(0)
W
0

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.

Woadwaxen answered 3/4, 2021 at 10:48 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.