Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to cancel multiple networking requests using Moya

I am currently using Moya to structure my networking calls. Per their docs, I have configured it as the following:

enum SomeAPIService {
    case endPoint1(with: Object)
    case endPoint2(duration: Int)
}

When calling an endpoint (in this case, endPoint1), I do the following:

let provider = MoyaProvider<SomeAPIService>()
provider.request(.endPoint1(object: object)) { (result) in
switch result {
    case let .success(moyaResponse):
        finished(Result.success(value: moyaResponse.value))
    case let .failure(error):
        let backendError = BackendError(localizedTitle: "", localizedDescription: "Some error", code: moyaResponse.statusCode)
        finished(Result.failure(error: backendError))
    }
})

My goal is, upon the user performing an action, cancel all the networking requests that's happening.

Accordingly, Moya does allow one to cancel requests from the discussion here. From the most upvoted comment, someone mentioned let request_1 = MoyaRequestXXXXX and then ruest_1.cancel()

My problem is:

  1. How would I keep pointer to the requests?
  2. provider doesn't have a cancel() function - so how should I be calling it?

Any help is much appreciated.

Edit:

Per the helpful suggestion about using [Cancellable], I did the following:

(1) In my app's singleton instance called Operator, I added var requests = [Cancellable]() (2) Every API call is added to the requests array as a Cancellable, like so:

let provider = MoyaProvider<SomeAPIService>()
Operator.shared.requests.append(provider as! Cancellable) //causing error
provider.request(.endPoint1(object: object)) { (result) in
//rest of the block omitted 

I think I am not getting the syntax correct, and am adding the provider and not the request. However, since the request is itself a block, where would be the place to add the request?

like image 797
daspianist Avatar asked Jul 21 '17 00:07

daspianist


2 Answers

The request method returns a Cancellable. From the documentation we can read:

The request() method returns a Cancellable, which has only one public function, cancel(), which you can use to cancel the request.

So according to this, I made a simple test and call:

var requests: [Cancellable] = []
@objc func doRequests() {
    for i in 1...20 {
        let request = provider.request(MyApi.someMethod) {
            result in
            print(result)
        }
        requests.append(request)
    }
    requests.forEach { cancellable in cancellable.cancel() } // here I go through the array and cancell each request.
    requests.removeAll()
}

I set up a proxy using Charles and it seems to be working as expected. No request was sent - each request was cancelled.

So, the answer to your questions is:

  1. You can keep it in [Cancellable] array.
  2. Go through the array and cancel each request that you want to cancel.

EDIT

The main problem is that you adding the provider to the array and you try to map provider as Cancellable, so that cause the error. You should add reqest to the array. Below you can see the implementation.

let provider = MoyaProvider<SomeAPIService>()
let request = provider.request(.endPoint1(object: object)) { // block body }
Operator.shared.requests.append(request)
//Then you can cancell your all requests.
like image 125
kamwysoc Avatar answered Nov 04 '22 23:11

kamwysoc


I would just cancel the current provider session + tasks:

provider.manager.session.invalidateAndCancel()
like image 20
zero3nna Avatar answered Nov 05 '22 00:11

zero3nna