11

I'm fetching xml data from server by using NSURLSession and NSURLSessionDelegate. Depends on some conditions I'm connecting with server. If I'm connecting with server everything works fine without any error but if I'm not connecting (depends on condition) to server and moving to another View Controller (by using storyboard?.instantiateViewControllerWithIdentifier(id)) I'm getting the following IOS error:

'A background URLSession with identifier backgroundSession already exists!'

Here is my code:

class MainClass: UITableViewController, NSURLSessionDelegate {     

   var task_service = NSURLSessionDataTask?()

   override func viewDidLoad() {
      super.viewDidLoad()

      if(condition) {
        getXMLFromServer()
      }

   }

   func getXMLFromServer(){

     task_service = getURLSession().dataTaskWithRequest() {

        (data, response, error) -> Void in

        dispatch_async(dispatch_get_main_queue(), {

         // Fetching data from server 

         // In the end
         self.session.invalidateAndCancel()
       }
    }

  }

 func getURLSession() -> NSURLSession {

    let configuration =      NSURLSessionConfiguration.defaultSessionConfiguration()

    configuration.timeoutIntervalForRequest = 30.0

    session = NSURLSession(configuration: configuration, delegate: self, delegateQueue: NSOperationQueue.mainQueue())

    return session
  }

 func URLSession(session: NSURLSession, task: NSURLSessionTask, didReceiveChallenge challenge: NSURLAuthenticationChallenge, completionHandler: (NSURLSessionAuthChallengeDisposition, NSURLCredential?) -> Void) {

    completionHandler(NSURLSessionAuthChallengeDisposition.UseCredential, NSURLCredential(forTrust: challenge.protectionSpace.serverTrust!)) // Bypassing SSL error
 }   
}

EDIT: Found the reason for the error.

Error occurred because of the creation of NSURLSession in the Called View Controller.Called VC contains code to download PDF from server. But I don't know how to solve this. Below is the code of Called VC

class MainFormsController: UIViewController, UIPickerViewDelegate, UITextFieldDelegate, NSURLSessionDownloadDelegate, UIDocumentInteractionControllerDelegate, MFMailComposeViewControllerDelegate{

 var download_task = NSURLSessionDownloadTask?()
 var backgroundSession = NSURLSession()

 override func viewDidLoad() {
    super.viewDidLoad()

     createNSURLSession()
 }               

 /** Error occurred while creating this NSURLSession **/

    func createNSURLSession() { 

        let backgroundSessionConfiguration =  NSURLSessionConfiguration.backgroundSessionConfigurationWithIdentifier("backgroundSession")

       backgroundSession = NSURLSession(configuration:   backgroundSessionConfiguration, delegate: self, delegateQueue:   NSOperationQueue.mainQueue())
    }

  func downloadPDF() {

     //Download PDF
     download_task = backgroundSession.downloadTaskWithURL(url)
     download_task?.resume()
  }

}
vsvishnu
  • 133
  • 1
  • 2
  • 11

3 Answers3

12

Add this code in your MainFormsController:

deinit {
        self.backgroundSession.finishTasksAndInvalidate();
    }
zlib
  • 300
  • 2
  • 8
5

Your code probably calls createNSURLSession() more than once which invalidate the NSURLSession behavior, as documentation says:

"You must create exactly one session per identifier (specified when you create the configuration object). The behavior of multiple sessions sharing the same identifier is undefined."

https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/URLLoadingSystem/Articles/UsingNSURLSession.html

Make sure createNSURLSession is called only once (singletone) for the life cycle of your app.

Amir Aharon
  • 291
  • 2
  • 9
  • This worked for me, thanks. I have URLSessions that get suspended and resumed. I was re-creating the session each time the download needed to resume. The solution was to store the session, and create a new task instead. – Luke Van In Apr 25 '18 at 14:58
  • @LukeVanIn can u provide code sample for reference? – jayant rawat Aug 02 '19 at 06:47
0

I think you already have an URLSession with identifier backgroundSession. First Call

- (void)invalidateAndCancel

on that. and then try with your code.

Ujjwal Khatri
  • 716
  • 1
  • 6
  • 19
  • Thanks for your response. I have tried this but no luck. I have edited my question. – vsvishnu Mar 22 '16 at 12:15
  • Suppose you are moving from A view Controller to B view controller. Now probably you are calling the invalidateAndCancel form the current view controller i.e. B, and the session was created in first view controller i.e. A. since the B view controller won't have the ownership of that session, it can not call invalidateAndCancel method on that. Please check. Thanks. – Ujjwal Khatri Mar 22 '16 at 12:20
  • I created session in VC A and connecting server from the same VC. At the end of fetching data I wrote 'self.session.invalidateAndCancel()'. After all these things when I call VC B (on a button click) there is no issues but if I'm not connecting to server and when I call VC B I got that error. Hope you can understand. – vsvishnu Mar 22 '16 at 12:30
  • can you try giving some unique identifier in your getURLSession method to the configuration object using '(backgroundSessionConfigurationWithIdentifier(_: )' – Ujjwal Khatri Mar 22 '16 at 12:52