This post is part of my udacity iOS Nanodegree program. I recognize it’s beginner stuff. ūüôā¬†

Let’s say you need to grab some data from a server in your iOS app. Here’s a method I discovered on the Hello iOS Swift blog which illustrates a great way to download an .mp3 and store it locally on your iOS device from your app. I am using their code, but also going a little further into explaining what that code is doing.

We’ll start the process by making sure we’re saving the file in iOS’ Document directory, inside the sandbox.

lazy var localMp3URL: NSURL = {
let fileManager = NSFileManager.defaultManager()
let documentURLs = fileManager.URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask)
let docURL: NSURL = documentURLs.last as! NSURL
let fileURL = docURL.URLByAppendingPathComponent("KRM-Christmas-Dinner.mp3")
return fileURL
}()

We’re wrapping this in a lazy var – which¬†means the¬†initial value of the localMp3URL variable is not calculated until the first time it is used. By using¬†let¬†for the fileManager, documentURLs, docURL, and fileURL values, we’re saying they won’t change – they’re constant. var and let both define values, but vars can change.

Before we download the .mp3 (a tongue-in-cheek song I wrote long ago while stuck in Florida alone for Christmas, with my family in Seattle), it’s wise for us to make sure this file isn’t already sitting in the location we’re trying to download it to.

if (fileManager.fileExistsAtPath(localMp3URL.path!) == false) {
downloadMp3()
} else {
println("the mp3 already exists in the download location")
}
}

We haven’t yet defined downloadMp3, but we’ll get to that later. This code basically says, if that file isn’t already where we’re trying to put it, run whatever downloadMp3 is. If the file exists, let’s print a message saying the mp3 already exists in the download location. For now that message would only be in the debug section area. We can guess the downloadMp3¬†function’s purpose… it probably downloads an .mp3.

If you read the NSURLSession documentation, we can see it allows for multiple tasks to happen simultaneously. Let’s create a session and task for our download.

var urlSession: NSURLSession!

let conf = NSURLSessionConfiguration.defaultSessionConfiguration()
self.urlSession = NSURLSession(configuration: conf)

This declares a new variable of urlSession, and a key of conf.

Now, we need a function to actually do the download. This is where we’ll define¬†downloadMp3 we referenced earlier.

func downloadMp3() {

let remoteURL = NSURL(string: "http://kylematthews.me/mp3/KRM-Christmas-Dinner.mp3")

let dlTask = urlSession.downloadTaskWithURL(remoteURL!) { location, response, error in
if (error == nil) {
let res = response as! NSHTTPURLResponse
if (res.statusCode == 200) {
let fileManager = NSFileManager.defaultManager()

var error: NSError?
if (fileManager.moveItemAtURL(location, toURL: self.mp3URL, error: &error) == false) {
println(error)
}
}
else {
println(res)
let desc = NSHTTPURLResponse.localizedStringForStatusCode(res.statusCode);
println(desc)
}
}
else {
println(error)
}
}

dlTask.resume()}

This is a bunch of code, and the formatting on my blog makes it even harder to read through. Sorry!

Essentially, we’re defining a constant URL for the .mp3 file (with the¬†remoteURL keyword), and then creating a¬†dlTask download task to download the file at that URL. We make sure there’s a 200 HTTP request (meaning there is something at that URL), then put that file in the Documents¬†directory of the device.

We’ve also created a couple error messages. In our else statement when we look for the 200 error (meaning what happens if we DON’T get a 200), we’re declaring¬†desc as the actual HTTP response we got back from the server instead, and our¬†println message there simply shows the server response. We could further clarify this by adding “The server returned an error. Here is what we received:” and then listing the server’s response.

But, if everything works, we’ve downloaded the file! This doesn’t actually DO anything with it, but hey, that’s the subject of another post.

Kyle Matthews