0
votes

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

1
Your issue is that your switch is based on type (a parameter to the closure), whereas your if statements are based on the isShipping and isBilling fields of $0.address. If type is .billing, and $0.isBilling is false, then no assignment will be done, and item will be nil. - Alexander
yes, am aware of this, what is the best way to handle this ? thanks. - Mohamed ALOUANE
To answer that, I'd need more context as to what your'e trying to achieve. What's type, and what does it mean for it to match or not match the value of $0.address.isX? - Alexander
Ironically, on this line var item : AddressItemViewModel! if you removed the ! from the end of it, the compiler would have told you that it was going to crash and why. - Daniel T.

1 Answers

1
votes

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
      }
    }