Search code examples
iosswiftalamofire

Alamofire Background Service, Global Manager? Global Authorisation Header?


Can anyone tell me how to use the Alamofire background service correctly?

My attempts are:

Login View Controller

// Create a global variable for the manager
var manager = Alamofire.Manager()
var configuration = NSURLSessionConfiguration()


class LoginViewController: UIViewController {

    // set the configuration for the manager
          configuration = NSURLSessionConfiguration.backgroundSessionConfigurationWithIdentifier("com.xxx.app.backgroundService")
          configuration.sharedContainerIdentifier = "com.xxx.app.backgroundService"
}

Now creating my login attempt, when successful go to the MainViewController and do here some more Requests.

 manager.request(.POST, "\(serviceUrl)public/service/authenticate", parameters: ["email": txtEmail.text!, "password": txtPassword.text!]) {
   ......
}

Here ill get my token for all requests, so ill add the to my global configuration:

class MainViewController: UIViewController {
     if let token: AnyObject = NSUserDefaults.standardUserDefaults().objectForKey("token") {
        configuration.HTTPAdditionalHeaders = ["Authorization": "Bearer \(token)"]
        manager = Alamofire.Manager(configuration: configuration)
    }
}

But now when ill logout and login again - ill get the following errors:

Warning: A background URLSession with identifier xxx.xxx.app.backgroundService already exists!

And the app crashes with:

*** Terminating app due to uncaught exception 'NSGenericException', reason: 'Task created in a session that has been invalidated'
*** First throw call stack:

So i really dont know how do use the background-service to get the following result:

At login attempt, i dont need to add an authentication header. But then, i would like to add it to every request. All requests should run as background service.

Can anyone help me out, how to solve that in a correct way? Thanks in advance!


Solution

  • You have multiple problems. The first is that you need to pass the configuration object into the Manager initializer. Otherwise you are not using the configuration for the underlying URL session in the Manager instance.

    The second issue is that you should NOT set header values on a configuration after it has been applied to a Manager instance. The Apple docs specifically call this out. We also call this out in our README. If you need to deal with authorization tokens, you need to pass them as a header attached to the actual request.


    Update #1

    Here's a small example showing how you could create a Manager instance that could be used globally.

    class NetworkManager {
        var authToken = "1234" // You'll need to update this as necessary
    
        let manager: Manager = {
            let configuration: NSURLSessionConfiguration = {
                let identifier = "com.company.app.background-session"
                let configuration = NSURLSessionConfiguration.backgroundSessionConfigurationWithIdentifier(identifier)
                return configuration
            }()
    
            return Manager(configuration: configuration)
        }()
    
        static let sharedInstance = NetworkManager()
    }
    
    class ExampleClass {
        func startNetworkRequest() {
            let headers = ["Authorization": NetworkManager.sharedInstance.authToken]
    
            NetworkManager.sharedInstance.manager.request(.GET, "https://httpbin.org/get", headers: headers)
                .responseJSON { response in
                    debugPrint(response)
                }
        }
    }
    

    You'll still need to work out how to update the authToken when it expires, but this shows one way how you could use your manager instance throughout your codebase.