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 in Stormy app: My iconView is returning an nil error when I unwrap it (!)...

I'm using Xcode 6.3, which might be part of the problem. I've figured out many of the differences and changes, but this one I can't figure out.

let downloadTask: NSURLSessionDownloadTask = sharedSession.downloadTaskWithURL(forecastURL!, completionHandler: { (location: NSURL!, response:NSURLResponse!, error: NSError!) -> Void in
            //this code might be causing a crash. Looks like this version is different than video

            if (error == nil) {
                let dataObject = NSData(contentsOfURL: location)

                let weatherDictionary: NSDictionary = NSJSONSerialization.JSONObjectWithData(dataObject!, options: nil, error: nil) as! NSDictionary

                let currentWeather = Current(weatherDictionary: weatherDictionary)
                dispatch_async(dispatch_get_main_queue(), { () -> Void in
                    self.temperatureLabel.text = "\(currentWeather.temperature)"
                    self.iconView.image = currentWeather.icon
                    self.currentTimeLabel.text = "At \(currentWeather.currentTime!) it is"
                    self.humidityLabel.text = "\(currentWeather.humidity)"
                    self.precipitatinLabel.text = "\(currentWeather.precipProbability)"
                    self.summaryLabel.text = "\(currentWeather.summary)"

                    //Stop refresh animation
                    self.refreshActivityIndicator.stopAnimating()
                    self.refreshActivityIndicator.hidden = true
                    self.refreshButton.hidden = false

                })


            } 


        })

        downloadTask.resume()

    }

There should be a ! after self.iconView.image = currentWeather.icon, but when I put it there, it returns nil and none of the others update. The app shows all the placeholders.

More pertinent code. I've checked with Dark Sky documentation, and all the case names are correct.

func weaterIconFromString(stringIcon: String) -> UIImage {
        var imageName: String

        switch stringIcon {
            case "clear-day":
                imageName = "clear-day"
            case "clear-night":
                imageName = "clear-night"
            case "rain":
                imageName = "rain"
            case "snow":
                imageName = "snow"
            case "sleet":
                imageName = "sleet"
            case "wind":
                imageName = "wind"
            case "fog":
                imageName = "fog"
            case "cloudy":
                imageName = "cloudy"
            case "partly-cloudy-day":
                imageName = "partly-cloudy"
            case "partly-cloudy-night":
                imageName = "cloudy-night"
        default:
                imageName = "default"

        }
        var iconImage = UIImage(named: imageName)
        return iconImage!

    }

Thank you for your help.

1 Answer

Hi Christine

Sorry to be a pain but is there any chance you could post all of the code you've currently got in your ViewController file just so I can have a full looksie at it for you?

Sure! You're not a pain at all. :) Thanks for your help!

ViewController:

//
//  ViewController.swift
//  Stormy
//
//  Created by Christine Rose on 4/8/15.
//  Copyright (c) 2015 Christine Rose. All rights reserved.
//

import UIKit

class ViewController: UIViewController {

    @IBOutlet weak var iconView: UIImageView!
    @IBOutlet weak var currentTimeLabel: UILabel!
    @IBOutlet weak var temperatureLabel: UILabel!
    @IBOutlet weak var humidityLabel: UILabel!
    @IBOutlet weak var precipitatinLabel: UILabel!
    @IBOutlet weak var summaryLabel: UILabel!


    @IBOutlet weak var refreshButton: UIButton!
    @IBOutlet weak var refreshActivityIndicator: UIActivityIndicatorView!

    //keep API private via Access Controls
    private let apiKey = "e20b62c84b9c30a04d37bc81be771eb3"



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

        refreshActivityIndicator.hidden = true
        getCurrentWeatherData()


    }

    func getCurrentWeatherData() -> Void {

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

        let weatherData = NSData(contentsOfURL: forecastURL!, options: nil, error: nil)

        let sharedSession = NSURLSession.sharedSession() //singleton, global object, use sparingly

        let downloadTask: NSURLSessionDownloadTask = sharedSession.downloadTaskWithURL(forecastURL!, completionHandler: { (location: NSURL!, response:NSURLResponse!, error: NSError!) -> Void in
            //this code might be causing a crash. Looks like this version is different than video

            if (error == nil) {
                let dataObject = NSData(contentsOfURL: location)

                let weatherDictionary: NSDictionary = NSJSONSerialization.JSONObjectWithData(dataObject!, options: nil, error: nil) as! NSDictionary

                let currentWeather = Current(weatherDictionary: weatherDictionary)
                dispatch_async(dispatch_get_main_queue(), { () -> Void in
                    self.temperatureLabel.text = "\(currentWeather.temperature)"
                    self.iconView.image = currentWeather.icon
                    self.currentTimeLabel.text = "At \(currentWeather.currentTime!) it is"
                    self.humidityLabel.text = "\(currentWeather.humidity)"
                    self.precipitatinLabel.text = "\(currentWeather.precipProbability)"
                    self.summaryLabel.text = "\(currentWeather.summary)"

                    //Stop refresh animation
                    self.refreshActivityIndicator.stopAnimating()
                    self.refreshActivityIndicator.hidden = true
                    self.refreshButton.hidden = false

                })


            } 


        })

        downloadTask.resume()

    }



    @IBAction func refresh() {

        getCurrentWeatherData()

        refreshButton.hidden = true
        refreshActivityIndicator.hidden = false
        refreshActivityIndicator.startAnimating()

    }

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


}

Current file:

//
//  Current.swift
//  Stormy
//
//  Created by Christine Rose on 4/10/15.
//  Copyright (c) 2015 Christine Rose. All rights reserved.
//

import Foundation
import UIKit


struct Current {
    var currentTime: String?
    var temperature: Int
    var humidity: Double
    var precipProbability: Double
    var summary: String
    var icon: UIImage?

    init(weatherDictionary: NSDictionary) {
        let currentWeather = weatherDictionary["currently"] as! NSDictionary

        temperature = currentWeather["temperature"] as! Int
        humidity = currentWeather["humidity"] as! Double
        precipProbability = currentWeather["precipProbability"] as! Double
        summary = currentWeather["summary"] as! String


        let currentTimeIntValue = currentWeather["time"] as! Int
        currentTime = dateStringFromUnixtime(currentTimeIntValue)

        let iconString = currentWeather["icon"] as! String

    }

    func dateStringFromUnixtime(unixTime: Int) -> String {
        let timeInSeconds = NSTimeInterval(unixTime)
        let weatherDate = NSDate(timeIntervalSince1970: timeInSeconds)

        let dateFormatter = NSDateFormatter()
        dateFormatter.timeStyle = .ShortStyle

        return dateFormatter.stringFromDate(weatherDate)

    }

    func weaterIconFromString(stringIcon: String) -> UIImage {
        var imageName: String

        switch stringIcon {
            case "clear-day":
                imageName = "clear-day"
            case "clear-night":
                imageName = "clear-night"
            case "rain":
                imageName = "rain"
            case "snow":
                imageName = "snow"
            case "sleet":
                imageName = "sleet"
            case "wind":
                imageName = "wind"
            case "fog":
                imageName = "fog"
            case "cloudy":
                imageName = "cloudy"
            case "partly-cloudy-day":
                imageName = "partly-cloudy"
            case "partly-cloudy-night":
                imageName = "cloudy-night"
        default:
                imageName = "default"

        }
        var iconImage = UIImage(named: imageName)
        return iconImage!

    }



}