Mohamed ALOUANE
Mohamed ALOUANE

Reputation: 5407

switch cases in Observable map Rxswift

I have in a viewmodel a reactive closure to return and sort data from a network call based on type (shipping or billing).

Observable.combineLatest(input.headerRefresh, type).flatMapLatest({ (header, type) -> Observable<[AddressItemViewModel]> in
    var els : Observable<[AddressItemViewModel]>

     els = self.request()
        .trackActivity(self.loading)
        .trackActivity(self.headerLoading)
        .trackError(self.error)

    return els.map{
        $0.map {
            print(type)
            var item  : AddressItemViewModel!
            switch(type){
            case .shipping:
                if($0.address.isShipping){
                    item = AddressItemViewModel(with: $0.address)
                }

            case .billing:
                if($0.address.isBilling){
                    item = AddressItemViewModel(with: $0.address)
                }
            }

            return item // error
        }
    }

   }).subscribe(onNext: { (items) in
        elements.accept(items)
    }).disposed(by: rx.disposeBag)

When subscribed to elements in the view controller, the app crash at return item.

So my question is how to sort items without using nullable objects? Thanks.

The error :

Thread 1: Fatal error: Unexpectedly found nil while unwrapping an Optional value

Upvotes: 0

Views: 881

Answers (1)

Maciej Gad
Maciej Gad

Reputation: 1741

The problem might be this line:

var item  : AddressItemViewModel!

Using implicitly unwrapped variable can lead to fatal error. Think what happens when your type is set to .shipping and $0.address.isShipping is set to false (or type is billing and $0.address.isBilling is false)? The item variable will be set to nil, but the type of item require to be a non-nil. I think the best option will be to use compactMap instead of map to pass only non-nil values:

 $0.compactMap {
      switch(type){
           case .shipping where $0.address.isShipping:
                fallthrough
           case .billing where $0.address.isBilling:
               return AddressItemViewModel(with: $0.address)
           default:
               return nil
      }
    }

Upvotes: 1

Related Questions