Home > Back-end >  Show error response in alert RxSwift using Driver
Show error response in alert RxSwift using Driver

Time:12-13

How to get an error response with driver so I can show it in alert. When I see the trait driver is can't error out, so should I use subject or behaviourRelay to get error response when I subscribe. Actually I like how to use driver but I don't know how to passed error response using driver.

this is my network service

func getMovies(page: Int) -> Observable<[MovieItem]> {
        
        return Observable.create { observer -> Disposable in
            self.service.request(endpoint: .discover(page: page)) { data, response, error in
                if let _ = error {
                    observer.onError(MDBError.unableToComplete)
                    return
                }
                
                guard let response = response as? HTTPURLResponse, response.statusCode == 200 else {
                    observer.onError(MDBError.invalidResponse)
                    return
                }
                
                guard let data = data else {
                    observer.onError(MDBError.invalidData)
                    return
                }
                
                if let decode = self.decode(jsonData: MovieResults.self, from: data) {
                    observer.onNext(decode.results)
                }
                observer.onCompleted()
            }
            return Disposables.create()
        }
    }

This is my viewModel

protocol ViewModelType {
    associatedtype Input
    associatedtype Output
    
    func transform(input: Input) -> Output
}

class PopularViewModel: ViewModelType {
    
    struct Input {
        let viewDidLoad: Driver<Void>
    }
    
    struct Output {
        let loading: Driver<Bool>
        let movies: Driver<[MovieItem]>
    }
    
    private let service: NetworkDataFetcher
    
    init(service: NetworkDataFetcher = NetworkDataFetcher(service: NetworkService())) {
        self.service = service
    }
    
    func transform(input: Input) -> Output {
        let loading = ActivityIndicator()
        let movies = input.viewDidLoad
            .flatMap { _ in
                self.service.getMovies(page: 1)
                    .trackActivity(loading)
                    .asDriver(onErrorJustReturn: [])
            }
        
        let errorResponse = movies

        
        return Output(loading: loading.asDriver(),movies: movies)
    }
}

this is how I bind the viewModel in viewController

let input = PopularViewModel.Input(viewDidLoad: rx.viewDidLoad.asDriver())
        
        let output = viewModel.transform(input: input)
        
        output.movies.drive { [weak self] movies in
            guard let self = self else { return }
            self.populars = movies
            self.updateData(on: movies)
        }.disposed(by: disposeBag)
        
        
        
        output.loading
            .drive(UIApplication.shared.rx.isNetworkActivityIndicatorVisible)
            .disposed(by: disposeBag)

CodePudding user response:

You do this the same way you handled the ActivityIndicator...

The ErrorRouter type below can be found here.

This is such a common pattern that I have created an API class that takes care of this automatically.

class PopularViewModel: ViewModelType {

    struct Input {
        let viewDidLoad: Driver<Void>
    }

    struct Output {
        let loading: Driver<Bool>
        let movies: Driver<[MovieItem]>
        let displayAlertMessage: Driver<String>
    }

    private let service: NetworkDataFetcher

    init(service: NetworkDataFetcher = NetworkDataFetcher(service: NetworkService())) {
        self.service = service
    }

    func transform(input: Input) -> Output {
        let loading = ActivityIndicator()
        let errorRouter = ErrorRouter()

        let movies = input.viewDidLoad
            .flatMap { [service] in
                service.getMovies(page: 1)
                    .trackActivity(loading)
                    .rerouteError(errorRouter)
                    .asDriver(onErrorRecover: { _ in fatalError() })
            }

        let displayAlertMessage = errorRouter.error
            .map { $0.localizedDescription }
            .asDriver(onErrorRecover: { _ in fatalError() })

        return Output(
            loading: loading.isActive.asDriver(onErrorRecover: { _ in fatalError() }),
            movies: movies,
            displayAlertMessage: displayAlertMessage
        )
    }
}
  • Related