Welcome to the Treehouse Community

The Treehouse Community is a meeting place for developers, designers, and programmers of all backgrounds and skill levels to get support. Collaborate here on code errors or bugs that you need feedback on, or asking for an extra set of eyes on your latest project. Join thousands of Treehouse students and alumni in the community today. (Note: Only Treehouse students can comment or ask questions, but non-students are welcome to browse our conversations.)

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and a supportive community. Start your free trial today.

iOS Build a Weather App with Swift (Retired) Displaying Our Weather Data Connecting the UI to Our Model

Michael Doyle
Michael Doyle
2,418 Points

NSUnknownKeyExeption for the key humidity?

Here is the ViewController.swift code:

import UIKit

class ViewController: UIViewController {

    // links to labels

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


    private let apiKey = "3a365c222ac8e460cdff4d4514dfe407"

    override func viewDidLoad() {
        super.viewDidLoad()

        // Do any additional setup after loading the view, typically from a nib.

        //let forecastURL = "https://api.forecast.io/forecast/3a365c222ac8e460cdff4d4514dfe407/39.630016,-76.331865"

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

        //the following code makes our request syncronous and would tie up the app - not good
        // we want asyncronous code so we can use multiple threads of execution simultaneously

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


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

            // test to see if we are getting data from the URL
           // var urlContents = NSString(contentsOfURL: forecastURL!, encoding: NSUTF8StringEncoding, error: nil)
            //println(urlContents)

            // want to hold contents in a file

            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.precipitationLabel.text = "\(currentWeather.precipProbability)"
                    self.summaryLabel.text = "\(currentWeather.summary)"              
                })

            }

        })

        downloadTask.resume()        

    }

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

}

Here is the Current.swift code:

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
        println(temperature)
        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
        icon = weatherIconFromString(iconString)

    }


    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 weatherIconFromString(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!

    }


}

Here is the error text in the debug window:

2015-01-20 18:44:51.024 Stormy[25638:5639254] *** Terminating app due to uncaught exception 'NSUnknownKeyException', reason: '[<Stormy.ViewController 0x7fb6fd906c80> setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key humidity.'
*** First throw call stack:
(
    0   CoreFoundation                      0x0000000100a29f35 __exceptionPreprocess + 165
    1   libobjc.A.dylib                     0x000000010256dbb7 objc_exception_throw + 45
    2   CoreFoundation                      0x0000000100a29b79 -[NSException raise] + 9
    3   Foundation                          0x0000000100e417b3 -[NSObject(NSKeyValueCoding) setValue:forKey:] + 259
    4   CoreFoundation                      0x0000000100973e80 -[NSArray makeObjectsPerformSelector:] + 224
    5   UIKit                               0x000000010157ac7d -[UINib instantiateWithOwner:options:] + 1506
    6   UIKit                               0x00000001013d9f98 -[UIViewController _loadViewFromNibNamed:bundle:] + 242
    7   UIKit                               0x00000001013da588 -[UIViewController loadView] + 109
    8   UIKit                               0x00000001013da7f9 -[UIViewController loadViewIfRequired] + 75
    9   UIKit                               0x00000001013dac8e -[UIViewController view] + 27
    10  UIKit                               0x00000001012f9ca9 -[UIWindow addRootViewControllerViewIfPossible] + 58
    11  UIKit                               0x00000001012fa041 -[UIWindow _setHidden:forced:] + 247
    12  UIKit                               0x000000010130672c -[UIWindow makeKeyAndVisible] + 42
    13  UIKit                               0x00000001012b1061 -[UIApplication _callInitializationDelegatesForMainScene:transitionContext:] + 2628
    14  UIKit                               0x00000001012b3d2c -[UIApplication _runWithMainScene:transitionContext:completion:] + 1350
    15  UIKit                               0x00000001012b2bf2 -[UIApplication workspaceDidEndTransaction:] + 179
    16  FrontBoardServices                  0x0000000103cec2a3 __31-[FBSSerialQueue performAsync:]_block_invoke + 16
    17  CoreFoundation                      0x000000010095f53c __CFRUNLOOP_IS_CALLING_OUT_TO_A_BLOCK__ + 12
    18  CoreFoundation                      0x0000000100955285 __CFRunLoopDoBlocks + 341
    19  CoreFoundation                      0x0000000100954a43 __CFRunLoopRun + 851
    20  CoreFoundation                      0x0000000100954486 CFRunLoopRunSpecific + 470
    21  UIKit                               0x00000001012b2669 -[UIApplication _run] + 413
    22  UIKit                               0x00000001012b5420 UIApplicationMain + 1282
    23  Stormy                              0x000000010043580e top_level_code + 78
    24  Stormy                              0x000000010043584a main + 42
    25  libdyld.dylib                       0x0000000102d47145 start + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException
(lldb)

I also see this in the AppDelegate.swift highlighted green right after @UIApplicationMain:

class AppDelegate: UIResponder, UIApplicationDelegate {

2 Answers

Michael Doyle
Michael Doyle
2,418 Points

Had to go back and delete the label in the main view. Then re-ad and re-connect. Then it worked. Not sure why.

I'm having the exact same issue; however, when a deleted and re-added the label in main view it did not fix the issue for me. Here is my viewController code: <body> import UIKit

class ViewController: UIViewController {

private let apiKey = "54e25f5e21f8faa088f12deffe0ada4f"


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


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: "33.613349,-117.899449", 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

            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.temperatureLabel.text = "\(currentWeather.temperature)"
                self.humidityLabel.text = "\(currentWeather.humidity)"
                self.precipitationLabel.text = "\(currentWeather.precipProbability)"
                self.summaryLabel.text = "\(currentWeather.summary)"
            })


        }
    })

    downloadTask.resume()
}


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

} </body>

here is the current code:

<body>

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
    icon = weatherIconFromString(iconString)
}

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 weatherIconFromString(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 = "partly-cloudy"
        default:
            imageName = "default"
    }

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

}

</body>

and here is the error I'm receiving:

<body>

2015-03-27 10:31:21.865 Stormy[12762:1144886] *** Terminating app due to uncaught exception 'NSUnknownKeyException', reason: '[<Stormy.ViewController 0x7fa04a638290> setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key precipitationLevel.' *** First throw call stack: ( 0 CoreFoundation 0x000000010027da75 exceptionPreprocess + 165 1 libobjc.A.dylib 0x0000000101dd5bb7 objc_exception_throw + 45 2 CoreFoundation 0x000000010027d6b9 -[NSException raise] + 9 3 Foundation 0x0000000100698d43 -[NSObject(NSKeyValueCoding) setValue:forKey:] + 259 4 CoreFoundation 0x00000001001c75e0 -[NSArray makeObjectsPerformSelector:] + 224 5 UIKit 0x0000000100dd74ed -[UINib instantiateWithOwner:options:] + 1506 6 UIKit 0x0000000100c35a88 -[UIViewController _loadViewFromNibNamed:bundle:] + 242 7 UIKit 0x0000000100c36078 -[UIViewController loadView] + 109 8 UIKit 0x0000000100c362e9 -[UIViewController loadViewIfRequired] + 75 9 UIKit 0x0000000100c3677e -[UIViewController view] + 27 10 UIKit 0x0000000100b55509 -[UIWindow addRootViewControllerViewIfPossible] + 58 11 UIKit 0x0000000100b558a1 -[UIWindow _setHidden:forced:] + 247 12 UIKit 0x0000000100b61f8c -[UIWindow makeKeyAndVisible] + 42 13 UIKit 0x0000000100b0c0c2 -[UIApplication _callInitializationDelegatesForMainScene:transitionContext:] + 2732 14 UIKit 0x0000000100b0ee3e -[UIApplication _runWithMainScene:transitionContext:completion:] + 1349 15 UIKit 0x0000000100b0dd35 -[UIApplication workspaceDidEndTransaction:] + 179 16 FrontBoardServices 0x0000000103987243 __31-[FBSSerialQueue performAsync:]_block_invoke + 16 17 CoreFoundation 0x00000001001b2c7c __CFRUNLOOP_IS_CALLING_OUT_TO_A_BLOCK + 12 18 CoreFoundation 0x00000001001a89c5 __CFRunLoopDoBlocks + 341 19 CoreFoundation 0x00000001001a8785 __CFRunLoopRun + 2389 20 CoreFoundation 0x00000001001a7bc6 CFRunLoopRunSpecific + 470 21 UIKit 0x0000000100b0d7a2 -[UIApplication _run] + 413 22 UIKit 0x0000000100b10580 UIApplicationMain + 1282 23 Stormy 0x000000010009779e top_level_code + 78 24 Stormy 0x00000001000977da main + 42 25 libdyld.dylib 0x00000001025b1145 start + 1 ) libc++abi.dylib: terminating with uncaught exception of type NSException (lldb)

</body>