Moya: Xcode error with new requestClosure in 7.0

Created on 14 Jul 2016  Â·  20Comments  Â·  Source: Moya/Moya

My request closure looks like this:

let requestClosure = { (endpoint: Moya.Endpoint<ICanHazProvider>, done: Result<NSURLRequest, Moya.Error> -> Void) in
  let request = endpoint.urlRequest.mutableCopy() as! NSMutableURLRequest

  if let token = self.getToken() {
    request.setValue(token, forHTTPHeaderField: "token")
  }

  return done(.Success(request))
}

hazAPI = MoyaProvider<ICanHazProvider>(endpointClosure: endpointClosure, requestClosure: requestClosure)

I'm getting the following error in Xcode now:

Unable to infer closure return type in current context

Is there any secret to getting this to work?

question

Most helpful comment

@ashfurrow Well, as I was preparing the example project, I realized that if I omit the variable type declarations in the closure it seems to compile and work fine. So I changed

let requestClosure = { (endpoint: Moya.Endpoint<ICanHazProvider>, done: Result<NSURLRequest, Moya.Error> -> Void) in
  let request = endpoint.urlRequest.mutableCopy() as! NSMutableURLRequest

  if let token = self.getToken() {
    request.setValue(token, forHTTPHeaderField: "token")
  }

  return done(.Success(request))
}

to

let requestClosure: MoyaProvider<ICanHazProvider>.RequestClosure = { endpoint, done in
  let request = endpoint.urlRequest.mutableCopy() as! NSMutableURLRequest

  if let token = self.getToken() {
    request.setValue(token, forHTTPHeaderField: "token")
  }

  done(.Success(request))
}

All 20 comments

When you get this error, the next step is usually to specify the return type explicitly. Looking at the Moya source code, you can change your line to the following:

let requestClosure = { (endpoint: Moya.Endpoint<ICanHazProvider>, done: Result<NSURLRequest, Moya.Error> -> Void) -> Void in

Let us know how it goes!

Now gives me this error:

Cannot convert value of type '(ICanHazProvider) -> Endpoint<ICanHazProvider>' to expected argument type '_ -> Endpoint<_>'

My endpoint looks like this:

let endpointClosure = { (target: ICanHazProvider) -> Endpoint<ICanHazProvider> in

  let url = target.baseURL.URLByAppendingPathComponent(target.path).absoluteString

  var encoding: Moya.ParameterEncoding = .JSON

  switch target.method {
  case .GET:
    encoding = .URL
  default:
    encoding = .JSON
  }

  let endpoint: Endpoint<ICanHazProvider> = Endpoint<ICanHazProvider>(URL: url, sampleResponseClosure: {.NetworkResponse(200, target.sampleData)}, method: target.method, parameters: target.parameters, parameterEncoding: encoding)

  return endpoint
}

I should clarify a bit: Error is on the next line:

hazAPI = MoyaProvider<ICanHazProvider>(endpointClosure: endpointClosure, requestClosure: requestClosure)

Having a related issue.

If I have this:

private let authenticatedRequestClosure =  {
    (endpoint: Endpoint<SmartContactsPluginService>, done: MoyaProvider.RequestResultClosure) in
    let request = endpoint.urlRequest

    GlobalOAuth.authenticateRequest(request, completion: {
        result in
        switch result {
        case .Success(let signedInRequest):
            done(Result<NSURLRequest, Moya.Error>.Success(signedInRequest))

        case .Failure(let error):
            done(Result<NSURLRequest, Moya.Error>.Failure(.Underlying(error)))
        }
    })
}

It gives me:

screen shot 2016-07-22 at 17 01 46

But if I have this:

private let authenticatedRequestClosure =  {
    (endpoint: Endpoint<SmartContactsPluginService>, done: Result<NSURLRequest, Moya.Error> -> Void) in
    let request = endpoint.urlRequest

    GlobalOAuth.authenticateRequest(request, completion: {
        result in
        switch result {
        case .Success(let signedInRequest):
            done(Result<NSURLRequest, Moya.Error>.Success(signedInRequest))

        case .Failure(let error):
            done(Result<NSURLRequest, Moya.Error>.Failure(.Underlying(error)))
        }
    })
}

It gives me:

screen shot 2016-07-22 at 17 04 31

I think I'm lost too with the same error for endpointClosure. I'm out of ideas :(
screen shot 2016-07-25 at 09 11 25

UPDATE:
I've tried to use this in the Demo.xcworkspace project and it also fails with the exact same reason:

 let endpointClosure: MoyaProvider.EndpointClosure = { (target: GitHub) -> Endpoint<GitHub> in
            let url = target.baseURL.URLByAppendingPathComponent(target.path).absoluteString
            let endpoint: Endpoint<GitHub> = Endpoint<GitHub>(URL: url, sampleResponseClosure: {.NetworkResponse(200, target.sampleData)}, method: target.method, parameters: target.parameters)
            return endpoint.endpointByAddingHTTPHeaderFields(["APP_NAME": "MY_AWESOME_APP"])
        }

@ashfurrow Is this a known issue or are we all doing something wrong? Any help would be greatly appreciated.

Yup, taking a look now. I've not seen this before, things are working for me with the latest master branch with Xcode 7.3.1. Have you run pod install in the Demo directory? What version of CocoaPods are you using?

@bryanbartow I think the second example might be getting confused with the nils used as parameters (they're non-optional, just remove them and they'll fallback to the defaults). But that doesn't explain the first error.

I'm really at a loss on that one. Would it be possible to share a small Xcode project demonstrating the problem? It would help figure out what the problem is.

@ashfurrow Well, as I was preparing the example project, I realized that if I omit the variable type declarations in the closure it seems to compile and work fine. So I changed

let requestClosure = { (endpoint: Moya.Endpoint<ICanHazProvider>, done: Result<NSURLRequest, Moya.Error> -> Void) in
  let request = endpoint.urlRequest.mutableCopy() as! NSMutableURLRequest

  if let token = self.getToken() {
    request.setValue(token, forHTTPHeaderField: "token")
  }

  return done(.Success(request))
}

to

let requestClosure: MoyaProvider<ICanHazProvider>.RequestClosure = { endpoint, done in
  let request = endpoint.urlRequest.mutableCopy() as! NSMutableURLRequest

  if let token = self.getToken() {
    request.setValue(token, forHTTPHeaderField: "token")
  }

  done(.Success(request))
}

Awesome! So that works? Where do you think we should document this?

@bryanbartow your problem might be returning the Result type in the closure that takes Void as a return type. Below code works under Xcode 7.3.1 & Moya 7.0.0:

let requestClosure = { (endpoint: Moya.Endpoint<ICanHazProvider>, done: MoyaProvider.RequestResultClosure) in
    let request = endpoint.urlRequest.mutableCopy() as! NSMutableURLRequest

    done(.Success(request))
}

@kamil-tomaszewski: @ashfurrow is right, when you specify nil in the rest of the parameters, Xcode throws not-so-specific error. When you remove the parameters with nil it should be good with the code below:

let endpointClosure = { (target: GitHub) -> Endpoint<GitHub> in
    let url = target.baseURL.URLByAppendingPathComponent(target.path).absoluteString
    let endpoint: Endpoint<GitHub> = Endpoint<GitHub>(URL: url, sampleResponseClosure: {.NetworkResponse(200, target.sampleData)}, method: target.method, parameters: target.parameters)
    return endpoint.endpointByAddingHTTPHeaderFields(["APP_NAME": "MY_AWESOME_APP"])
}

About @dccarmo issue I'm kinda lost as well ¯_(ツ)_/¯ Might try omitting the Result type in done callback, like done(.Success(result)) and try if it works? Otherwise could you provide us an example project where the issue exists? Would be really helpful.

@sunshinejr Changing my code to your suggestion yields the error in my original post in this issue:

Unable to infer closure return type in current context

@ashfurrow @sunshinejr I'm starting to wonder if this has something to do with the Result library, which I'm using elsewhere in my project...

@sunshinejr omitting the Result type did the trick, thanks!

@bryanbartow Yeah, we've had issues before when using multiple Result identifiers. You can use modules names to namespace the specific Result type, like Result.Result or MyLibrary.Result, it can get tricky. Let us know how it goes :+1:

So - the issue is really weird.
If you do:

let endpointClosure = { (target: GitHub) -> Endpoint<GitHub> in
            let url = target.baseURL.URLByAppendingPathComponent(target.path).absoluteString
            let endpoint: Endpoint<GitHub> = Endpoint<GitHub>(URL: url, sampleResponseClosure: {.NetworkResponse(200, target.sampleData)}, method: target.method, parameters: target.parameters)
            return endpoint
        }

 _ = MoyaProvider<GitHub>(endpointClosure: endpointClosure)

Everything is peachy.
If you pass all the parameters, even if you copy them from the default implementation of init it gets the above result. So:

  1. The issue isn't with endpointClosure.
  2. Issue is with Xcode? compiler? I have no idea and unfortunately after being stuck for one day with this I don't have more time to dig deeper

@kamil-tomaszewski It could be that in the original code, you had let endpointClosure: MoyaProvider.EndpointClosure without specifying the generic type of MoyaProvider and it confused the type system? Try let endpointClosure: MoyaProvider<GitHub>.EndpointClosure and see what happens. (It works if you don't specify anything because the compiler can infer from the closure signature what MoyaProvider's generic type is.)

It seems the issue here has been solved, so I guess this issue can be closed, right?

@BasThomas I would think so. Not sure about everyone else, but my issue has been resolved and I'm the original reporter ;)

@ashfurrow thanks let endpointClosure: MoyaProvider.EndpointClosure can slove it, but
MoyaProvider.RequestClosure can not

Was this page helpful?
0 / 5 - 0 ratings