0

I am using RxSwift in swift. When my server is close it shows below error with blank screen. I have used a alert. But I have to click too many time to close the alert here is the error

enter image description here

I have implemented RxSwift below like

  1. Data Model

      struct LoginDto : Decodable {
    
        let outCode: String
        let outMessage: String
    
        enum CodingKeys: String, CodingKey {
            case outCode = "outCode"
            case outMessage = "outMessage"
    
        init(from decoder: Decoder) throws {
            let values = try decoder.container(keyedBy: CodingKeys.self)
            outCode = try values.decodeIfPresent(String.self, forKey: .outCode) ?? ""
            outMessage = try values.decodeIfPresent(String.self, forKey: .outMessage) ?? ""
    
        }
    }
    
  2. Common Error handling

     import RxSwift
     import Alamofire
      class ErrorViewModel {
        static let shared = ErrorViewModel()
        let publishSubject = PublishSubject<ErrorResponse>()
        var errorResponse: Observable<ErrorResponse> {
            return publishSubject.asObservable()
        }
    
       // private init() {}
    }
    
  3. View Model

    import RxSwift
    import Alamofire
    class LoginViewModelV{
    
    private let loginSubject = PublishSubject<LoginDto>()
    var LoginResponse: Observable<LoginDto> {
        return loginSubject.asObservable()
    }
    
     func doLogin(`var` parameters: [String: Any]) {
    
            AF.request("htt://myurl/login", method: .post, parameters:parameters,
                       encoding: JSONEncoding.default,
                       headers: "myheader")
    
                .validate(statusCode: 200..<500)
                .responseDecodable(of: LoginDto.self) { [weak self] response in
    
                    switch response.result {
                    case .success:
                        switch response.response!.statusCode {
                        case 200:
                            if let v_response = response.value {
                                  self?.loginSubject.onNext(v_response)
                            }
                        default:
                            let ex =  ErrorHandling.exception(statusCode:response.response?.statusCode)
                            ErrorViewModel.shared.publishSubject.onNext(ex)
                        }
                    case .failure(let error):
                        let ex =  ErrorHandling.exception(error: error,statusCode:response.response?.statusCode)
                        ErrorViewModel.shared.publishSubject.onNext(ex)
    
                    }
    
                }
        }
    }
    
  4. Here ViewController

     import UIKit
     import RxSwift
     class LoginViewController: UIViewController {
    
    var loginViewModel = LoginViewModelV()    
    private let disposeBag = DisposeBag()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        doLogin()
        observeEvents()
    }
    
    func observeEvents(){
        self.loginViewModel.LoginResponse
            .subscribe(onNext: { response in
                // here is login
    
            })
            .disposed(by: self.disposeBag)
    
        ErrorViewModel.shared.publishSubject.subscribe(onNext: { err in
            Custom_Progress_bar.hide()
            /***
             I have use here sweet alert
             */
         //   Custom_Sweet_alert.show_error_message(messsage: err.message)
    
        }).disposed(by: self.disposeBag)
    }
    
    func doLogin(){
    
        let parameters: [String: Any] = [
            "userId": "myuserId",
            "passowrd": "mypasswor"
        ]
    
        loginViewModel.doLogin(var:parameters)
     }
    
    }
    

when server is off, observeEvents method LoginViewController in alert shows with blank screen. I have use ErrorViewModel to get all common error like network or others. What is the wrong of my code? Please help to solve the problem...

Enamul Haque
  • 4,789
  • 1
  • 37
  • 50

1 Answers1

0

The likely problem here is that your ErrorViewModel.publishSubject is emitting more than once. You will have to track that down.

But in general, you are working way too hard here. Let's simplify your code by using my Cause_Logic_Effect library. You can import the library through Cocoapods or SPM.

import Cause_Logic_Effect
import RxSwift
import UIKit

struct LoginDto: Decodable {
    let outCode: String
    let outMessage: String
}

class LoginViewModelVI {
    static func doLogin(parameters: [String: Any]) -> Observable<LoginDto> {
        Observable.create { observer in
            AF.request("htt://myurl/login", method: .post, parameters:parameters, encoding: JSONEncoding.default, headers: "myheader")
                .validate(statusCode: 200..<500)
                .responseDecodable(of: LoginDto.self) { response in
                    switch response.result {
                    case .success:
                        if let value = response.value, response.response!.statusCode == 200 {
                            observer.onSuccess(value)
                        } else {
                            observer.onError(ErrorHandling.exception(statusCode:response.response?.statusCode))
                        }
                    case .failure(let error):
                        observer.onError(ErrorHandling.exception(error: error,statusCode:response.response?.statusCode))
                    }
                }
            return Disposables.create()
        }
    }
}

class LoginViewController: UIViewController {
    let userIdField = UITextField()
    let passwordField = UITextField()
    let loginButton = UIButton()
    let activityTracker = ActivityTracker()
    let errorRouter = ErrorRouter()
    private let disposeBag = DisposeBag()

    override func viewDidLoad() {
        super.viewDidLoad()
        bind()
    }

    func bind() {
        loginButton.rx.tap
            .withLatestFrom(Observable.combineLatest(userIdField.rx.text, passwordField.rx.text))
            .flatMapFirst { [activityTracker, errorRouter] userId, password in
                LoginViewModelVI.doLogin(parameters: [
                    "userId": "myuserId",
                    "passowrd": "mypasswor"
                ])
                .trackActivity(activityTracker)
                .rerouteError(errorRouter)
            }
            .subscribe(onNext: { response in
                // here is login
            })
            .disposed(by: disposeBag)

        errorRouter.error
            .subscribe(onNext: { err in
                /***
                 I have use here sweet alert
                 */
                //Custom_Sweet_alert.show_error_message(messsage: err.message)
            })
            .disposed(by: self.disposeBag)

        activityTracker.isActive
            .subscribe(onNext: { isActive in
                if isActive {
                    Custom_Progress_bar.show()
                } else {
                    Custom_Progress_bar.hide()
                }
            })
            .disposed(by: self.disposeBag)
    }
}
Daniel T.
  • 32,821
  • 6
  • 50
  • 72