Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

RxSwift + UserDefaults

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.
    }
}
like image 392
whisper Avatar asked Mar 18 '17 17:03

whisper


People also ask

What do you use UserDefaults for?

At runtime, you use UserDefaults objects to read the defaults that your app uses from a user's defaults database. UserDefaults caches the information to avoid having to open the user's defaults database each time you need a default value.

What is UserDefaults in Swift?

The UserDefaults class looks up the value for the key that is passed to the object(forKey:) method and returns a value if a value exists for the given key. It returns nil if no value exists for the given key. The UserDefaults class also defines a number of convenience methods for retrieving values of a specific type.

Is UserDefaults synchronous?

The beauty of this aspect of UserDefaults is that it still offers us a 100% synchronous API, even though changes are propagated to multiple apps or extensions asynchronously in the background.


2 Answers

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.

like image 93
Timofey Solonin Avatar answered Oct 02 '22 01:10

Timofey Solonin


iOS bug, v10.2

UserDefaults.standard.rx
    .observe(String.self, "key")
+   .debounce(0.1, scheduler: MainScheduler.asyncInstance)
    ...
like image 29
whisper Avatar answered Oct 02 '22 00:10

whisper