Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

iOS

Problem with Stormy code

This code worked recently, until an error popped up. It's on the letDownloadTask line and "forecastURL" is highlighted.. Can anyone please help? The error message just mentions inserting a "?" or a "!", so it isn't all that helpful.

import UIKit

class ViewController: UIViewController {

    private let apiKey = "437b62587a6adb3f888c27bd83305203"

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.

        let baseURL = NSURL(string: "https://api.forecast.io/forecast/\(apiKey)/")
        let forecastURL = NSURL(string: "37.8267,-122.423", relativeToURL:baseURL)
        let sharedSession = NSURLSession.sharedSession()
        let downloadTask: NSURLSessionDownloadTask = sharedSession.downloadTaskWithURL(forecastURL, completionHandler: { (location: NSURL!, response: NSURLResponse!, error: NSError!) -> Void in

            if (error == nil) {
                let dataObject = NSData(contentsOfURL:location)
            let weatherDictionary: NSDictionary = NSJSONSerialization.JSONObjectWithData(dataObject, options: nil, error: nil) as NSDictionary
                println(weatherDictionary)
            }

    })
    downloadTask.resume()

    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }


}

I kept running into the same issue during this tutorial, and although the addition of "!" to the end of my NSURL objects now allows the code to compile and run (thanks Ryan!), now my console output is simply returning "nil," as opposed to the URL response object seen in the tutorial.

Double-checked my forecast.io account and no calls have been made. Other than the unique API key and addition of "!" to unwrap my NSURL objects, my code appears to be identical to that in the tutorial. What else could I be missing here? Thought about making this a separate forum post, but I figured it was related to Jason's question, and it's at the exact same point in the tutorial. Any help would be greatly appreciated!

Hey Jaron,

I would like to help you out more. Could you post some code, I just recompiled my version of the completed project and it still runs, meaning no Swift changes.

let forecastURL = NSURL(string: "https://api.forecast.io/forecast/\(APIKey)/\(location)")

There is my version of the URL. So I'm thinking you may have and invalid API key, but providing your code would allow us to work this out! :)

Thanks for the quick response, Ryan! Here's the code I have so far, right after importing UIKit:

class ViewController: UIViewController {

    private let apiKey = "43e54a8b14d9f187c2e2c87d6876a7cb"

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.

        let baseURL = NSURL(string: "https://api.forecast.io/forecast/\(apiKey)/")
        let forecastURL = NSURL(string: "37.8267,-122.423", relativeToURL: baseURL!)

        let sharedSession = NSURLSession.sharedSession()
        let downloadTask: NSURLSessionDownloadTask = sharedSession.downloadTaskWithURL(forecastURL!, completionHandler: { (location: NSURL!, response: NSURLResponse!, error: NSError!) -> Void in
            println(response)
        })
        downloadTask.resume()
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }


}

My forecastURL is structured a little differently than yours, but probably just because I'm at an earlier point in the tutorial. I thought it might have been the API Key, but I just reset mine at forecast.io and plugged in the new key with no luck. Cross-checked it against the tutorial code a few times, and it appears to be identical in structure, but maybe a second set of eyes will catch something I missed :)

Hey Jaron,

I didn't see your reply until now, I just thought I'd try pasting in your code into a blank Single View Template in Xcode and your code is working for me!

Are you still experiencing issues with this?

Sorry I took so long to get back to you!

Hopefully you got it working though :)

1 Answer

Hey Jason!

Along with the release of iOS 8.1 and with Xcode 6.1, they updated parts of Swift that were questionable, for instance your bit of broken code is

let downloadTask: NSURLSessionDownloadTask = sharedSession.downloadTaskWithURL(forecastURL, completionHandler: { (location: NSURL!, response: NSURLResponse!, error: NSError!) -> Void in
            //...
        })

The reason this is now questionable is because Apple deemed a NSURL in Swift to be an optional type with the NSURL(string: "") declaration.

What this means is that you need to unwrap the optional value in your downloadTask constant.

sharedSession.downloadTaskWithURL(forecastURL! ...

My opinion on why Apple changed this is because URL's are always changing, or can fail pretty often, so it allows for the Swift language to try and prevent crashes!

Hope this helps :)

Thank you Ryan. That solved that issue, but the update to Xcode also necessitated my unwrapping this bit of code too:

   let weatherDictionary: NSDictionary = NSJSONSerialization.JSONObjectWithData(dataObject,

to:

   let weatherDictionary: NSDictionary = NSJSONSerialization.JSONObjectWithData(dataObject!,...

Yeah! and if/when you finish this project there is an image view that needs to be unwrapped and my guess is that anything with a path of that is representing data that can be non-existent will need to be unwrapped somewhere in the code unless other methods are used.

I'm sure Apple will update Swift again and end up breaking our apps so we will just have to keep learning :)