Alamofire: Reconnecting to In Progress Background Transfers

Created on 6 Feb 2016  ·  9Comments  ·  Source: Alamofire/Alamofire

Hi,

I have a question regarding how Alamofire works with in progress background transfers.

So, imagine this scenario:

  1. User opens up your app
  2. User queues up a collection of background transfers
  3. User backgrounds your app
  4. User launches other apps enough to force the system to terminate your app
  5. User relaunches your app while at least one of your previous background transfers were running.

Some questions here:

  1. Is this a realistic edge case?
  2. It looks like the existing Alamofire SessionDelegate multiplexes the delegate callbacks based on taskIdentifiers instead of by URL, which means that client code would have to recreate the tasks that were running apriori in order to match up by taskIdentifier again. (Seems like a very hacky, buggy solution).
  3. Apps would have to check at app launch to see if there are any background transfers that are running, and override Alamofire's SessionDelegate using the blocks.

The question I have with number 3 is if we should be removing the override once all background transfers have completed? What happens if the user starts new ones? In this scenario, it seems like I would be working around Alamofire's code a lot...

Thanks,

Ronak

question url session

Most helpful comment

It’s still accurate. We hope to create a solution for background transfers that integrates with other Alamofire technologies sometime after Alamofire 5 is out.

All 9 comments

Hi Ronak,

These are all fantastic questions. At the moment, Alamofire does not have very strong support for background downloads. You observations are all perfectly valid. Let me try to answer your questions one-by-one.

  1. Yes, this is a realistic case. You need to be able to handle this case properly, otherwise you can end up in a strange app state when you relaunch.
  2. If you want to use Alamofire for background downloads, you need to override the SessionDelegate task closures. When your app gets relaunched, you need to recreate your SessionDelegate and wire up the closures, then recreate the background URL session with the same identifier. This is more or less what you would do if you weren't using Alamofire. What you MUST remember is that you cannot rely on response closures that were attached to a Request. Since your app was terminated and relaunched, the Request objects no longer exist.

To use Alamofire with background downloads, you currently need to not use the response closures and override the SessionDelegate closures.

  1. You don't need to do this. You only need to recreate your background URL session when your app delegate is notified to application:handleEventsForBackgroundURLSession:completionHandler:. An easier approach may be to recreate the background URL session when your app is launched. But some people may feel that you should instead create the URL session lazily. Your call either way.

So, in summary, you can absolutely use background URL sessions with Alamofire. There is not as much convenience yet as there could be, but it can certainly be done. You need to make sure you don't use the response closures, and you need to override the task override closures in the SessionDelegate.

_Full Disclosure:_ If you are just downloading files in the background, I'd recommend you just create your own NSURLSession and NSURLSessionDelegate and wire it up yourself. The URL requests are easy to build since you really only need to pass a URL. There's just too much overhead on Alamofire for this use case. The Alamofire APIs are also designed around closures chained to the Request which doesn't work with background sessions.

Additionallly, this is already being worked on in #981. I'd encourage you to check it out and provide some feedback. I haven't had time to review that PR yet myself.

Thanks for the awesome question. Hopefully that helps clear some things up. Cheers. 🍻

It looks like you can continue to use the block structure you have now except for two things:

  1. Stop multiplexing from a nsurlsession task to a request object by using task identifiers. It would be better to multiplex by url. I don't ever imagine people would want to send multiple requests for the same url concurrently.
  2. You schedule the call to the background completion handler onto the utility queue, which dispatches back to main.

With these changes, people can continue to use the existing set up.

You would query your persistence store to see which downloads are still running, recreate the request objects. The rest runs as it always has.

What do you think?

I don't understand your reasoning here @ronak2121. First off, I don't understand what you mean by multiplexing in #1. As for #2, I don't understand what that accomplishes. Additionally, recreating requests is only easy if you have them completely abstracted and all callbacks are done using a delegate pattern, not closures.

What I mean by multiplexing is that you currently have a dictionary in the SessionDelegate where you map from NSURLSessionTask to Request using the task identifier.

That wouldn't hold up across app restarts since we lose the mapping from a Request Object to its task identifier. It would be better to use the url in that dictionary since the app would know which downloads are still in progress (assuming the app is keeping track in a persistence store of some kind) and can easily recreate the Request objects.

Te second point I was making was there is a slight threading concern with the way the request closures work in that they are dispatched to the set table queue.

The main points I am trying to make here are that I don't think you would have to re-engineer your code so much and tear it all up for this.

Sent from my iPhone

On Feb 9, 2016, at 12:31 AM, Christian Noon [email protected] wrote:

I don't understand your reasoning here @ronak2121. First off, I don't understand what you mean by multiplexing in #1. As for #2, I don't understand what that accomplishes. Additionally, recreating requests is only easy if you have them completely abstracted and all callbacks are done using a delegate pattern, not closures.


Reply to this email directly or view it on GitHub.

While I appreciate your feedback here, I respectfully disagree. There are MANY other complex things going on here. As mentioned before, we've put this into our backlog slated for Alamofire 4.0 to make sure we handle things properly. We'll take all this feedback into consideration when we start working through our actual solution.

Cheers. 🍻

OK, had to spend a lot of time googling this to find this thread.

@cnoon any chance some of this information could make it into the documentation somewhere close to the section on background sessions? Currently it doesn't discuss anything about how this is a use-case Alamofire doesn't support directly / well, and it feels like it's something that should be addressed. Recognizing and understanding the complexities involved, so I'm not demanding a fix ASAP, but putting the documentation that this is just something AF cannot do currently would be helpful. I read backwards and forwards over the readme, and it explains how to configure a background session, but never why this isn't a good AF use-case.

Currently it's very easy to wander in, see that AF 'supports' background sessions, and get confused as to how to set it up -- and I could just as easily see someone trying to do it with AF and closures and getting confused by why it's not working at all. I was 'lucky', I realized there was no way at all closures could be restored properly, and started digging in to figure out WTF was going on.

For others who end up here when researching this issue, can @cnoon or anyone confirm whether or not, as of Alamofire 4, the following statement is still accurate? Thanks!

Full Disclosure: If you are just downloading files in the background, I'd recommend you just create your own NSURLSession and NSURLSessionDelegate and wire it up yourself. The URL requests are easy to build since you really only need to pass a URL. There's just too much overhead on Alamofire for this use case. The Alamofire APIs are also designed around closures chained to the Request which doesn't work with background sessions.

It’s still accurate. We hope to create a solution for background transfers that integrates with other Alamofire technologies sometime after Alamofire 5 is out.

Hoping to see it in Alamofire 5 :)

Was this page helpful?
0 / 5 - 0 ratings

Related issues

DrAma999 picture DrAma999  ·  3Comments

yamifr07 picture yamifr07  ·  3Comments

matthijsotterloo picture matthijsotterloo  ·  3Comments

lvandal picture lvandal  ·  3Comments

simonliotier picture simonliotier  ·  3Comments