Group Group Group Group Group Group Group Group Group

raywenderlich.com Forums

NSURLSession Tutorial: Getting Started

In this NSURLSession tutorial, you'll learn how to create HTTP requests, as well as implement background downloads that can be both paused and resumed.


This is a companion discussion topic for the original entry at http://www.raywenderlich.com/110458/nsurlsession-tutorial-getting-started

Hi, Ken,
Thanks for your tutorial! It’s very informative and I learned a lot.
I have a question for the NSURL though: how do we access each specific files in our local directory with NSURL class?
say if I want to build a tableview that can display all the downloaded contents, with also the functionality of deleting files, what should I do to get access to each files?
Thank you!

–Fred

Hi Ken,

I am an iOS newbie, and trying to teach on my own.
This is the most helpful NSURLSession tutorial I have discovered.
It answered most questions I have about doing multiple concurrent web service calls.

I have a few follow-up questions.

  1. Why did you choose to make the defaultSession (the NSURLSession object) a member variable of the SearchViewController class instead of initializing it only in the viewDidLoad() function?
  2. I want to understand the lifecycle of an iOS ViewController.
    a. If I have a ViewController that calls a web service (e.g., retrieving weather info from OpenWeather API) inside viewDidLoad(), do I need to do that all the time?
    b. How do I cache results and avoid calling the web service unnecessarily? In other words, how do I only make web service calls to retrieve new data only every 15 minutes or some arbitrary time limit?

It doesn’t need to be a full-detailed answer.
I can read up on my own if you can point me what topics to read up on.

Thanks for a great tutorial!
Soe

NSFileManager provides all the functionalities you need to open an application’s sandboxed directory path, enumerate the contents at that path, and manipulate the individual contents.

Do check out the following Apple documentation on the various functions you could use:

https://developer.apple.com/library/ios/documentation/Cocoa/Reference/Foundation/Classes/NSFileManager_Class/#//apple_ref/occ/instm/NSFileManager/subpathsOfDirectoryAtPath:error:

Hi stun,

  1. Technically, you could set defaultSession to be a var and initialize it in viewDidLoad() too, but since defaultSession is set once and never ever changed in our case, it’s considered good practice to declare it as a let constant initialized with a static value.

  2. viewDidLoad() is called whenever the controller first loads its view into the view hierarchy. If the controller unloads the view subsequently, then it’ll be called again when the controller has to load the view again. But note that this unloading would typically happen only when memory is running low on the device - under normal circumstances, even if the view becomes hidden or toggled away to another screen and back, the controller won’t unload the view.

    Based on the above, it’d be perfect to load your web service in viewDidLoad(), if you don’t want to have web service reloaded each time the view is shown. And if you like, you could then schedule a timer to retrieve new data to refresh the view at a rate that you desire.

    The other extreme would be to reload in viewWillAppear(), which is triggered whenever a view is shown (toggled away from another screen and back etc). This approach could be helpful if want to ensure that the data shown is always in sync.

Hope this helps!

Hi Ken

Really nice tutorial, the code works like a charm except for an issue i have.
When I navigate to another view and return to my download controller (where i have your code implemented) i receive this message “A background URLSession with identifier myBgSession already exists!” and my app stays showing the activity indicator forever. Any solution on this?!
I’m new to swift and iOS programming

Hi and thank you so much for this tutorial,

let configuration = NSURLSessionConfiguration.backgroundSessionConfigurationWithIdentifier(“bgSessionConfiguration”)
Note that you also set a unique identifier for the session here to allow you to reference and “reconnect” to the same background session if needed.

Can we get updates using:

func URLSession(session: NSURLSession, downloadTask: NSURLSessionDownloadTask, didWriteData bytesWritten: Int64, totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64)

from another class using this session identifier?

Start download files in one class, checking downloading process in another class?

Thank you.

Hi Ken

thanks for your tutorial,Let me learn a lot~

a little question:

if I want to download remote server pdf file, NSURLSession need something modify?
thanks for your reply!

Hi Ken

Thanks for the tutorial.

With respect to the following code,

// 2
let fileManager = NSFileManager.defaultManager()
do {
try fileManager.removeItemAtURL(destinationURL)
} catch {
// Non-fatal: file probably doesn’t exist
}

How can we handle the case where the file already exists and we need to replace the file with a new one?
For instance, if we have a PDF at the location/destinationURL and we modify it and re-run the code. The location will still have the older/modified version of the PDF from previous iteration. But we expect it to download and show a fresh PDF.

How can we use NSURLSession to implement the same?

Thanks in advance.
Ashish Hasija

Has anyone converted this to Objective-C? I’m not ready to make the leap to Swift just yet, but would like to learn how to do this in ObjC.

Hi Ken, cheers for the tutorial. I’ve tried it out with the latest xcode8-beta6 and ios10 simulator, and the resume functionality doesnt work. The output says Invalid resume data for background download. Background downloads must use http or https and must download to an accessible file.

Appears to be scoped to ios10. When I use an ios9 simulator device, resume works.

From the little I can find the resumeData blob looks valid when converted into a plist, has all the right keys.

But I did notice the path the partial file is stored in has changed from tmp/ to Library/Caches/com.apple.nsurlsessiond/Downloads/com.kentoh.HalfTunes/ so am guessing some kind of logic is needed to stitch this up when resuming.

Do you see this behavior? Do you have any ideas on how to resolve the path issue?

Cheers,
Ash

What a fabulous tutorial! It is beautifully designed to give the feedback you can expect if you work through it by adding a line at a time.

After adding code for the searchBarSearchButtonClicked function I got one warning.

step // 3

let searchTerm = searchBar.text!.stringByAddingPercentEncodingWithAllowedCharacters(expectedCharSet)!

Initialisation of immutable value ’searchTerm’ was never used; consider replacing with assignment to ‘’ or removing it._

I understand this warning to mean replace ‘let searchTerm’ with ‘_’ but I have been learning Swift for a fortnight so I might be missing something.

When I ran it on the simulator, there was no list like the second iPhone screen shot shown in the tutorial. My interpretation of the log in the debug window is that something breaks a connection after the code has successfully set it up. When I tried it again without editing the line in step 3, the same thing happened. I repeated the last step again on an iPhone 5C with a similar result.

I am mystified and welcome any suggestion. The only other thing I did was convert the code for the tutorial template to Swift 2.3. Converting this to Swift 3 didn’t work. I’m also using Xcode 8.0 Beta 6.

If it helps, I can send you the debug log. I didn’t want to post it here without asking first.

Thanks

Greg S

My initial problem may be related to Xcode 8 beta 6. When I reverted to Xcode 7.1.3 and started again (i.e. by unzipping the Starter project), Xcode did not offer to translate this into either Swift 2.3 or Swift 3 but created a build. When I followed the tutorial by adding code to populate the table view line by line, the app crashed. I was only able to populate the table view by cutting and pasting the block of code.
Greg S

I am also having trouble with this tutorial in XCode 8, and Swift 3.

Could you guys update your tutorial to support swift 3? thanks!

Hi thanks for nice tutorial. Give some more tutorials

Hello,
did you happen to solve this issue at any point? I used this tutorial as a foundation for a video streaming app at my work and now that I converted it to swift 3 my resume is broken.

Thank you
William

Hello,
did you happen to solve this issue at any point? I used this tutorial as a foundation for a video streaming app at my work and now that I converted it to swift 3 my resume function is broken. I am assuming you have the same issue.

Thank you
William

I also have the same issue where the resume function does not work after converting the project to Swift 3. The following error occur:

*** -[NSKeyedUnarchiver initForReadingWithData:]: data is NULL
*** -[NSKeyedUnarchiver initForReadingWithData:]: data is NULL
Invalid resume data for background download. Background downloads must use http or https and must download to an accessible file.

Does anyone have a solution for this problem?

Hi William, I did successfully manage to apply this crazy and impressive fix: http://stackoverflow.com/a/39347461/1012802.

I also encountered the issue where network loss now triggers a call to :didCompleteWithError on the session delegate, with no resumeData, but a NSLocalizedDescription of ‘unsupported URL’ and code=-1002. Apple docs say to either try to restart the task with resumeData, or to recreate the task. But I’m wondering if I can just call resume on the task, im not sure. Im still testing.

I’d be interested in your findings. And hopefully this bug gets resolved by apple soon!!

Thank you for the help. I still have to work the kinks, but the downloads now complete after the pause and resume are used. However, I still receive null data errors. I need to figure out what is actually going on with the added functions. And I am not entirely sure as to which occurrences of the original functions I should replace. Hopefully I will get it all worked out. I will have to tackle the network loss issue after that.