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.
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!
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.
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?
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.
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:
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.
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.
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
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.
// 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?
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?
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.
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
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.
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.
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.
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.