9
votes

The service I'm connecting to is using a self signed certificate. For dev purposes I do not want to validate that chain.

Using swift 3 with Alamofire 4. Fixed the ATS accordingly:

<key>NSAppTransportSecurity</key>
<dict>
    <key>NSExceptionDomains</key>
    <dict>
        <key>url.com</key>
        <dict>
            <key>NSExceptionAllowsInsecureHTTPLoads</key>
            <true/>
            <key>NSExceptionRequiresForwardSecrecy</key>
            <false/>
            <key>NSIncludesSubdomains</key>
            <true/>
        </dict>
    </dict>
</dict>

Code to connect and disable evaluation.

    let serverTrustPolicies: [String: ServerTrustPolicy] = [
        "example.domain.com": .pinCertificates(
            certificates: ServerTrustPolicy.certificates(),
            validateCertificateChain: false,
            validateHost: true
        ),
        "sub.url.com": .disableEvaluation
    ]

    let sessionManager = Alamofire.SessionManager(
        serverTrustPolicyManager: ServerTrustPolicyManager(policies: serverTrustPolicies)
    )

    let headers = ["Authorization": "Basic /*...*/"]

    sessionManager.request("https://sub.url.com/path", headers: headers).responseJSON { response in
        print(response.request)  // original URL request
        print(response.response) // HTTP URL response
        print(response.data)     // server data
        print(response.result)   // result of response serialization

        debugPrint(response)

        if let JSON = response.result.value {
            print("JSON: \(JSON)")
        }
    }

Error log from dumpPrint

[Result]: FAILURE: Error Domain=NSURLErrorDomain Code=-999 "cancelled" UserInfo={NSErrorFailingURLKey=https://sub.url.com/path, NSLocalizedDescription=cancelled, NSErrorFailingURLStringKey=https://sub.url.com/path}

URL has been masked.

6

6 Answers

13
votes

To retain SessionManager instance you need to capture it in closure passed to responseJSON:

sessionManager.request("https://sub.url.com/path", headers: headers).responseJSON { response in
    let _ = sessionManager // retain
    // ...
}

Otherwise sessionManager is deallocated shortly it goes out of scope and any executing requests are cancelled.

8
votes

Please add this statement to the end of responseJson block:

manager.session.invalidateAndCancel()

It happens if the object of the manager is not retained till execution of the block completes, so this would ensure its retention.

Cheers!

4
votes
self.getSessionManager().request(urlstring, method: methods, parameters: parameters, encoding: JSONEncoding.prettyPrinted, headers: Header).responseJSON(queue: nil, options: JSONSerialization.ReadingOptions.allowFragments) { (responseObject) in ... .... }.session.finishTasksAndInvalidate()

Just put the method of invalidate after task finish, means session.finishTasksAndInvalidate()

2
votes

Please check in sessiondidReceiveChallenge: delegate implementation of NSURLSession. Chances are NSURLSessionAuthChallengeCancelAuthenticationChallenge is getting executed somewhere.

1
votes

You need to properly manage the lifetime of your SessionManager instance. Most commonly this is done by making a singleton instance. Otherwise, when your manager goes out of scope and is deinited, all outstanding requests will be cancelled.

0
votes

There could be a lot of reason to why your requests "cancelled".
In your case your request cancels immediately. You can refer to this issue in Alamofire repository issues

jshier commented on Oct 10, 2016

An unexpected error -999 almost always means your SessionManager was deallocated, cancelling any ongoing requests. I suggest you create a singleton value for your custom SessionManager, or perhaps just reevaluate if you really need one.

if you create a singleton value for your object it remains in memory and prevent from deallocate

and another thing that i avoid is to name your variables diffrent, a sessionManager is in Alamofire and your variable is also called sessionManager.

Alamofire 4.7 , Swift 4

import Alamofire

class Networking {

  public static let sharedManager: SessionManager = {
      let configuration = URLSessionConfiguration.default
      configuration.timeoutIntervalForRequest=20
      let manager = Alamofire.SessionManager(configuration: configuration, delegate: SessionManager.default.delegate)
      return manager
  }()
}

Alamofire 5.4.4 , Siwft 5.2

import Alamofire

class Networking {

  static let APIManager: Session = {
      let configuration = URLSessionConfiguration.default
      configuration.timeoutIntervalForRequest = 20
      let delegate = Session.default.delegate
      let manager = Session.init(configuration: configuration,
                                 delegate: delegate,
                                 startRequestsImmediately: true,
                                 cachedResponseHandler: nil)
      return manager
  }()
}