10

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?

daspianist
  • 5,336
  • 8
  • 50
  • 94

2 Answers2

15

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.
kamwysoc
  • 6,709
  • 2
  • 34
  • 48
  • Thanks for the great suggestion. I added more in the question body as a response - it has to do with syntax in adding the requests. The main issue is the block syntax - the requests are blocks, and I don't know where it is appropriate to add the request in my `[Cancellable]` array. – daspianist Jul 21 '17 at 21:19
  • 1
    Ah perfect. Thanks so much! – daspianist Jul 21 '17 at 21:47
1

I would just cancel the current provider session + tasks:

provider.manager.session.invalidateAndCancel()
zero3nna
  • 2,770
  • 30
  • 28
  • 1
    I had a problem here, whereby if you want to make further requests afterwards after cancellation - on any other view controller, swift throws an error about previously invalidated requests. – Rowan Gontier May 16 '19 at 10:34
  • @RowanGontier this is a bit unspecific... alamofire is killing your session with `invalidateAndCancel()` for you so that you should not have any problems, like you describe. you should take a look at threading and dont handle network stuff in your viewControllers btw. – zero3nna May 16 '19 at 20:20
  • One difference for me, might be that I was using provider.rx, instead of provider.request. – Rowan Gontier May 17 '19 at 04:35