1

I am building an app targeting iOS 8.0 that needs to download files that are up to 250Mb. I had a version of the download code roughly working using Alamofire but I recently replaced that with a pure NSURLSession implementation. This new implementation is working as expected in the simulator and on my iPhone 5S running iOS 9.2 (13C75). It works on my phone whether I install through XCode and a physical connection or through TestFlight. I have deleted the app, restarted the phone, and reinstalled and it always completes downloads correctly. One of my colleagues pulled the code and was able to successfully simulate it from XCode.

However, downloads fail on all of my collaborators' devices. They are installing the app through TestFlight and are set up as internal testers. One collaborator also has a iPhone 5S running iOS 9.2 (13C75). The Alamofire-based implementation worked as intended when deployed through TestFlight to those same devices and very little other code has changed.

I have added some remote logging and I can see that on the failing devices, downloads are correctly triggered and the download tasks I create each have a taskIdentifier which I can log. However, none of the NSURLSessionDelegate or NSURLSessionDownloadDelegate methods are called.

What suggestions do you have for troubleshooting?

Is it possible that this could be related to a TestFlight problem? My current next step is to try an alternative to TestFlight. Ultimately, I would like to be able to deploy betas through TestFlight if possible.

I'm using Swift 2.1.1 in XCode 7.2 (7C68).

rmaddy
  • 314,917
  • 42
  • 532
  • 579
Hélène Martin
  • 1,409
  • 2
  • 15
  • 42
  • "none of the NSURLSessionDelegate or NSURLSessionDownloadDelegate" is the delegate added and if so is it retained properly? – Vig Dec 31 '15 at 14:57
  • It is added and those methods are called in the simulator and on my own physical device. I didn't think I had to do anything special to ensure retention in Swift but please let me know if there's anything I should be making sure to do for that! – Hélène Martin Dec 31 '15 at 15:06
  • 1
    You are right I forgot the fact it runs on simulator and devices. Also didn't realize it's swift.... Anyway all I can think of is to check AppTransportSecurity but again if it works on simulator then I think the issue is elsewhere – Vig Dec 31 '15 at 15:37
  • 1
    Any specific reason you are using your own delegate rather than a completion handler? Any code in `#if DEBUG` or similar sections? Are you using regular downloads, or background downloads? What object acts as delegate, and what is its lifecycle? The relevant parts of your code would probably also help... – jcaron Dec 31 '15 at 17:14
  • 1
    Difference between running app locally and loading from TF is build configuration. Try "Edit Schemes / Run / Build Configuration" then select Release then run it on your device. you should be able to see what is wrong. – modusCell Dec 31 '15 at 18:35
  • @jcaron, I'm using background downloads so I do need to use a delegate. I'm going to try what mohacs suggests and then see about adding more details to my question to address what you asked about. – Hélène Martin Dec 31 '15 at 20:28

1 Answers1

1

The problem turned out to be that I had set the NSURLSessionConfiguration discretionary property to true. The docs state the following which sounded good to me:

When transferring large amounts of data, you are encouraged to set the value of this property to true.

But I failed to appreciate the consequences of the rest of the text:

For example, the system might delay transferring large files until the device is plugged in and connected to the network via Wi-Fi.

The reason that installations through XCode were working was presumably that the phone was either being charged because it was connected to my computer when I started a download or had just been charged.

I initially suspected that the problem came from either TestFlight or something about the state of the phone. Remote logging with Sentry (which I already use for the backend) was very helpful for getting some insights into what was different when my collaborators ran the app. I eventually added in implementations for all the NSURLSessionDownloadDelegate methods to log which ones were called. This led me to see that didReceiveChallenge was the only delegate method being called and I then spent some time thinking that it could be an auth-related problem and troubleshooting in that general area.

Finally, I started noticing that my own install would fail sometimes and one collaborator had a successful download. That made me start thinking about the kind of phone state that could prevent a download. I went back to the NSURLSession configuration that I had and that's when I read about the discretionary property.

In retrospect, carefully checking the configuration would have been a good step to do earlier. Another good thing to do would have been to log the state property of the download tasks that were created.

Hélène Martin
  • 1,409
  • 2
  • 15
  • 42