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 Build a Weather App with Swift Simple Data Structures Bootstrapping the UI

Anthony Babich
Anthony Babich
5,505 Points

Why does my returned value say "Optional(80)" instead of "80" like it should? Please help.

So basically it is returning the correct value, found in my CurrentWeather.plist But the value returned isnt just "80" like the instructors. It's "Optional(80)" and it also says "Optional(80)" in the label.

How do I fix????????

import Foundation

struct CurrentWeather {

    let temperature : Int?
    let humidity : Int?
    let precipProbability : Int?
    let summary : String?

    init(weatherDictionary: [String : AnyObject]){
        temperature = weatherDictionary["temperature"] as? Int
        humidity = weatherDictionary["humidity"] as? Int
        precipProbability = weatherDictionary["precipProbability"] as? Int
        summary = weatherDictionary["summary"] as? String
    }
}
import UIKit

class ViewController: UIViewController {

    @IBOutlet weak var currentTemperatureLabel: UILabel?


    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        if let plistPath = NSBundle.mainBundle().pathForResource("CurrentWeather", ofType: "plist"),
        let weatherDictionary = NSDictionary(contentsOfFile: plistPath),
        let currentWeatherDictionary = weatherDictionary["currently"] as? [String:AnyObject]{
        let currentWeather = CurrentWeather(weatherDictionary: currentWeatherDictionary)
        currentTemperatureLabel?.text = "\(currentWeather.temperature)"
            print(currentWeather.temperature)

        }
}

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


}

2 Answers

Steven Deutsch
Steven Deutsch
21,046 Points

Hey Anthony Babich,

The reason the value is being displayed like that is because it is an optional value. If a value is capable of being an optional, it will have an optional wrapping. If you think of variables and constants as containers for values, you can think of optionals as a wrapper for those containers. To extract the value from one of these containers that is wrapped in an optional, we either have to perform optional binding or implicitly unwrap the optional. It is much safer to do an optional bind as opposed to forcefully unwrapping.

You can see in your data model (your CurrentWeather struct) that the temperature property is of type Optional Int. This means the value will always be wrapped in an optional because it is capable of being nil.

If you want to unwrap this optional, you can perform optional binding using an if let statement:

override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        if let plistPath = NSBundle.mainBundle().pathForResource("CurrentWeather", ofType: "plist"),
        let weatherDictionary = NSDictionary(contentsOfFile: plistPath),
        let currentWeatherDictionary = weatherDictionary["currently"] as? [String:AnyObject] {
            let currentWeather = CurrentWeather(weatherDictionary: currentWeatherDictionary)

            if let currentTemp = currentWeather.temperature {
                currentTemperatureLabel?.text = "\(currentTemp)"
            }
        }
}

Good Luck

Anthony Babich
Anthony Babich
5,505 Points

I really really appreciate your response. if you notice in my code it's essentially as follows:

if let (bundleinfo),
let weatherDictionary = NSDictionary,
let currentWeatherDictionary = weatherDictionary,
{ 
currentTemperatureLabel?.text = "\(currentWeather.temperature!)"
}

So because I have the if let in the beginning wouldnt it be safe for me to then force unwrap it?

I see what you did, you made ANOTHER if let statement inside of the if let statement for plist. Is that what would normally be done or did you overlook my if let statement? I'm really just wondering for clarity to ease my thoughts.

Thanks so much!!!

Steven Deutsch
Steven Deutsch
21,046 Points

It's not safe to forcefully unwrap there because there are only 3 things you safely unwrapped:

1) The plistPath has been safely unwrapped

2) The weatherDictionary has been safely unwrapped

3) The currentWeatherDictionary has been safely unwrapped

You then proceed to use that currentWeatherDictionary to create an instance of CurrentWeather by passing it to the initializer. You assign this instance to a constant called currentWeather.

This is all well and fine, however, the properties of currentWeather: temperature, humidity, summary, percipProbability, are all optional properties. This means you don't need to set these values to create an instance.

So when you created the instance of CurrentWeather using the dictionary, if it didn't have one of the values for this property then the value for these properties would be nil. That's why you need to use the if-let before you access these properties.

Anthony Babich
Anthony Babich
5,505 Points

Okay, gotcha. By using the if let we avoid forceful unwrap because that is best practice in the case of a nil crashing our app which we don't want to risk at all.

Anthony Babich
Anthony Babich
5,505 Points

So........ I'm probably just behind in Swift versions, because I'm on the most up-to-date Xcode. At least, behind as far as the lessons are concerned.

I was able to fix the problem by force unwrapping (which appears to be OK because I'm also using an if let statement to validate before taking any actions (i.e. unwrapping currentweather.temperature).

currentTemperatureLabel?.text = "\(currentWeather.temperature!)"
Steven Deutsch
Steven Deutsch
21,046 Points

It's rarely ever safe to forcefully unwrap :P Unless you've done an explicit check for nil beforehand. In this situation, its not safe to force unwrap because the previous optional bind has only safely checked the existence of the currentWeatherDictionary. This dictionary was used to create an instance of your CurrentWeather struct. It's still possible for the properties of this instance to be nil values. For example, the currentWeatherDictionary could have not had the necessary information to assign a value to the temperature property. In that case, your code would crash. Crashing is the worst possible thing your code can do!