Reputation: 6302
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?
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.
Upvotes: 7
Views: 4132
Reputation: 5679
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:
withLatestFrom
and get the latest status from your reachability service.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
Upvotes: 2