5 Replies
      Latest reply: Feb 14, 2017 8:12 AM by bombbombtom RSS
      bombbombtom Level 1 Level 1 (0 points)

        My app needs to upload data in the background, because there's potentially too much to complete while the app is in the foreground. It's getting close to working:

         

        • I'm using a background session via URLSessionConfiguration.background(withIdentifier: "name")
        • I start an upload task with this session
        • I put my app in the background and then launch other apps to get iOS to terminate mine due to memory pressure
        • I wait while the upload completes

         

        Later on, the app launches in the background, and

        • I get the expected call to application(_:, handleEventsForBackgroundURLSession:, completionHandler:)
        • I re-create my session as described above
        • I get a callback to urlSessionDidFinishEvents(forBackgroundURLSession:)

         

        So far so good, but I also need to be able to get some information that the server returns. I thought I could look up tasks on the session object and use those, but both getAllTasks(completionHandler:) and getTasksWithCompletionHandler(_:) give me empty arays for all closure arguments.

         

        What do I need to do to get the completion status for those tasks? Why can't I get the tasks from the session?

         

        iOS 10.2.1, iPhone 6

        • Re: Getting task responses after background connection finishes
          bombbombtom Level 1 Level 1 (0 points)

          Possibly (?) related: When iOS launches my app in the background, my app delegate receives application(_:,didFinishLaunchingWithOptions:) before it receives application(_:,handleEventsForBackgroundURLSession:,completionHandler:), and the code in the "did finish launching" callback will re-create the URLSession. I don't think this should be a problem because I'm still getting the call to urlSessionDidFinishEvents(forBackgroundURLSession:) as expected, but who knows?

           

          Also for what it's worth, the launch options includes the completely undocumented key "UIApplicationLaunchOptionsURLSessionKey". I'm not sure if I should be doing anything with that.

            • Re: Getting task responses after background connection finishes
              eskimo Apple Staff Apple Staff (6,470 points)

              You should get the -URLSession:task:didCompleteWithError: delegate callback (well, its Swift equivalent) for those tasks, before you get the -URLSessionDidFinishEventsForBackgroundURLSession:.  In that not happening?

              If you don’t put the app in the background — that is, hold it in the foreground until the tasks complete — do you get the ‘didCompleteWithError’ delegate callback then?


              I don't think this should be a problem …

              Correct.

              I'm not sure if I should be doing anything with that.

              You should not.  If it’s undocumented, it’s best to leave it alone.

              Share and Enjoy

              Quinn “The Eskimo!”
              Apple Developer Relations, Developer Technical Support, Core OS/Hardware
              let myEmail = "eskimo" + "1" + "@apple.com"

                • Re: Getting task responses after background connection finishes
                  bombbombtom Level 1 Level 1 (0 points)

                  I had not implemented that method. Normally I use per-task completion blocks when in the foreground, and it wasn't clear to me that I could expect that session delegate method to be called when launched in the background. That seems to be exactly what I need though. Thanks!

                    • Re: Getting task responses after background connection finishes
                      eskimo Apple Staff Apple Staff (6,470 points)

                      Normally I use per-task completion blocks when in the foreground …

                      Ah, yes, that’s a definite point of confusion.  The completion handler approach is not supported in background sessions because your app might be terminated and relaunched between the point where you start the task and the point where the task completes.  Completion handler blocks can capture arbitrary program state, so there’s no way to save and restore them across such a termination boundary.

                      Share and Enjoy

                      Quinn “The Eskimo!”
                      Apple Developer Relations, Developer Technical Support, Core OS/Hardware
                      let myEmail = "eskimo" + "1" + "@apple.com"

                        • Re: Getting task responses after background connection finishes
                          bombbombtom Level 1 Level 1 (0 points)

                          I understood that completion blocks wouldn't work for background re-launching, it was more a question of it being unclear which methods would be available in that situation. The docs made it clear that urlSessionDidFinishEvents(forBackgroundURLSession:) would be called, but I didn't realize that the per-task delegate methods would also be called.