How do I check for internet using Moya and RxSwift?
Asked Answered
P

1

7

As far as I understand Alamofire is pulled in with built in Reachability, so my own handler would look something like:

import Alamofire

let reachabilityManager = NetworkReachabilityManager()
reachabilityManager.listener = { status in

switch status {

case .notReachable:
 print("The network is not reachable")
 self.onInternetDisconnection()

case .unknown :
 print("It is unknown whether the network is reachable")
 self.onInternetDisconnection() // not sure what to do for this case

case .reachable(.ethernetOrWiFi):
 print("The network is reachable over the WiFi connection")
 self.onInternetConnection()

case .reachable(.wwan):
 print("The network is reachable over the WWAN connection")
 self.onInternetConnection()

 }
}

I'm making a request with:

let provider = MoyaProvider<MyMoyaRequest>()
let token = provider.request(.start(
    username:self.email.value, 
    password: self.password.value) { result in

    switch result { 
    case let .success(moyaResponse):
        //handle success
    case let .failure(error):
        //handle failure
    }
}

So if I want to have connectivity checked before every Moya Request is made what is the best way to go about it?

  1. Write an extension for one of Moyas internals to check first
  2. Use the Moya plugin (prepare) to check
  3. Some fancy pants other way so far unthought of...

I specifically do not want to add a reachability check to every single API call, for readability reasons. But I am interested in hearing about methods previously used.

Thank-you for any assistance you can offer.

Pollypollyanna answered 25/10, 2017 at 12:27 Comment(0)
D
2

I specifically do not want to add a reachability check to every single API call

It might be a reasonable decision to wrap all you API calls into some service. For example how I did it in my last app:

public protocol NetworkServiceType: class {
    /// Cancellable request
    func observableRequest<T,C>(api: AnyApi<T>, cancel: Observable<C>, headers: [AUApi.Header: String], indicator: ActivityRelay?, logs: NetworkServiceLogs, timeout: TimeInterval, queue: DispatchQueue) -> Observable<Output<T>>
}

As you can see the network service has a single function that is able accept all the necessary parameters. And when you wrap all your requests into a single function - you can add everything you want inside this function. Even reachability check!

I want to have connectivity checked before every Moya Request is made

There are some ways to do it:

  1. I'd create a shared reactive reachability service and inject this service in network service. So, before every Moya Request you can call withLatestFrom and get the latest status from your reachability service.
  2. You can create reachability service for each request and delete it after request is completed.

I'd love show you how to create the 2nd variant. The first thing we need is some ReachabilityInformer:

final class ReachabilityInformer: Disposable {

    private lazy var networkReachabilityManager: NetworkReachabilityManager? = NetworkReachabilityManager(host: "www.google.com")
    private lazy var relayNetworkReachable = PublishRelay<Bool>()

    init() {
        switch networkReachabilityManager {
        case .none:
            relayNetworkReachable.accept(false)
        case .some(let manager):
            manager.listener = { [weak informer = self] status in
                switch status {
                case .notReachable:
                    informer?.relayNetworkReachable.accept(false)
                case .unknown:
                    break
                case .reachable:
                    informer?.relayNetworkReachable.accept(true)
                }
            }
        }
        networkReachabilityManager?.startListening()
    }

    func observableReachable() -> Observable<Bool> {
        return relayNetworkReachable
            .asObservable()
            .distinctUntilChanged()
    }

    func dispose() {
        networkReachabilityManager?.stopListening()
        networkReachabilityManager?.listener = nil
        networkReachabilityManager = nil
    }
}

It should conform to Disposable because it will be used by using operator.

So, how to use it:

Observable<Bool>
    .using({ ReachabilityInformer() }, observableFactory: { (informer: ReachabilityInformer) -> Observable<Bool> in
        return informer.observableReachable()
    })

The request should be started using this Observable. If connections exists true you should flatMap to your Moya Request. If it is false, then you should return a failure or throw an error. When request is completed, using operator will make sure that the ReachabilityInformer is deallocated.

P.S. Not tested, just some information to think about

Dm answered 5/7, 2018 at 6:36 Comment(3)
Hello @iWheelBuy, I am little confused about above code could you please explainCormophyte
@MeSolutionanalysts Sorry, I don't have enough time to provide you with a detailed answer.Dm
I've added startListening() and stopListening() calls, does't work otherwiseAquiver

© 2022 - 2024 — McMap. All rights reserved.