skip to Main Content

Hi i’m just getting started with RxSwift and decided to make simple Currency Exchange application. My app has two view’s (allCurrenciesList and userFavouritesView). Basically all logic works, but only if i run networking func every single time one of view didAppear/didLoad. My point is two fetch it only once, and received many times, when necessary. Application fetch dictionary of currencies and in ViewModel pass it to BehaviorSubject, and when view being load/appear it just subscribe it, and use it in UITableView. Thanks

class ListViewModel {
    
    let service: CurrencyService!
    var curriencies = BehaviorRelay<[Currency]>(value: [])
    var currienciesObservable: Observable<[Currency]> {
        return curriencies.asObservable().share()
    }
    let disposeBag = DisposeBag()
 
    init(service: CurrencyService) {
        self.service = service
    }
    
    func fetchAllCurrencies() {
      
            self.service.fetchAllSymbols { result in
                switch result{
                case .success(let currencies):
                    self.dictionaryIntoArray(currencies: currencies["symbols"] as! [String : Any])
                case .failure:
                    print("error")
                    
                }
            }
    }
    
    private func dictionaryIntoArray(currencies: [String: Any]) {
        var currencyArray = [Currency]()
        for (symbol, name) in currencies {
            currencyArray.append(Currency(symbol: symbol, fullName: name as! String))
        }
        let sortedArray = currencyArray.sorted { $0.fullName < $1.fullName }
        self.curriencies.accept(sortedArray)
    } 

allCurrenciesList

override func viewDidLoad() {
        super.viewDidLoad()
        setupView()
        configureTableViewDataSource()
        tableView.delegate = self
        fetchData()
    }
    
    private func fetchData() {
        viewModel.fetchAllCurrencies() // this func is necceserry everysingle time 
        viewModel.currienciesObservable.subscribe(onNext: { curriencies in
            self.applySnapshot(curriencies: curriencies)
        }).disposed(by: disposeBag)
    }

userFavouritesView

 override func viewDidLoad() {
        super.viewDidLoad()
       
        viewModel.fetchAllCurrencies() // this func is necceserry everysingle time 
        viewModel.currienciesObservable.subscribe(onNext: { allCurencies in
            let selectedItems = UserDefaults.standard.array(forKey: "SelectedCells") as? [Int] ?? [Int]()
            var currenciesArray: [Currency] = []
            selectedItems.forEach { int in
                self.pickerValues.append(allCurencies[int])
                currenciesArray.append(allCurencies[int])
            }
            self.applySnapshot(curriencies: currenciesArray)
        }).disposed(by: disposeBag)
        
    }

2

Answers


  1. The key here is to not use a Subject. They aren’t recommended for regular use. Just define the currienciesObservable directly.

    Something like this:

    class ListViewModel {
        let currienciesObservable: Observable<[Currency]>
    
        init(service: CurrencyService) {
            self.currienciesObservable = service.rx_fetchAllSymbols()
                .map { currencies in
                    currencies["symbols"]?.map { Currency(symbol: $0.key, fullName: $0.value as! String) }
                        .sorted(by: { $0.fullName < $1.fullName }) ?? []
                }
        }
    }
    
    extension CurrencyService {
        func rx_fetchAllSymbols() -> Observable<[String: [String: Any]]> {
            Observable.create { observer in
                self.fetchAllSymbols { result in
                    switch result {
                    case let .success(currencies):
                        observer.onNext(currencies)
                        observer.onCompleted()
                    case let .failure(error):
                        observer.onError(error)
                    }
                }
                return Disposables.create()
            }
        }
    }
    

    With the above, every time you subscribe to the currenciesObservable the fetch will be called.

    Login or Signup to reply.
  2. As I understand, it’s because your fetchAllSymbols function was not stored in the DisposeBag.

    func fetchAllCurrencies() {
        self.service.fetchAllSymbols { result in
             switch result{
                case .success(let currencies):
                    self.dictionaryIntoArray(currencies: currencies["symbols"] as! [String : Any])
                case .failure:
                    print("error")
                    
             }
        }.dispose(by: disposeBag)
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search