Swift 2.0 Guard Statement Fails Struct Initializer

418 Views Asked by At

There was a similarly named topic but the example was an error due to user mistake. I believe this example is an actual XCode issue.

I was following a treehouse tutorial and in the spirit of swift 2.0 I used guard statements instead of if lets in the initializer. My code was identical to the instruction except for the use of guard statements. It had one error that said "return from initializer without initializing all stored properties". Once I changed it to if let statements, it worked. Perhaps I made a mistake somewhere but I stared at it for atleast an hour, no properties were left un-initialized.

I made the properties equal to nil in the else clauses just in case but that didnt affect anything.

struct DailyWeather {

let maxTemp: Int?
let minTemp: Int?
let humidity: Int?
let precipChance: Int?
var summary: String?
var icon: UIImage? = UIImage(named: "default.png")
var largeIcon: UIImage? = UIImage(named: "default_large.png")
var sunriseTime: String?
var sunsetTime: String?
var day: String?

let dateFormatter = NSDateFormatter()

init(dailyWeatherDictionary: [String:AnyObject]) {

    minTemp = dailyWeatherDictionary["temperatureMin"] as? Int
    maxTemp = dailyWeatherDictionary["temperatureMax"] as? Int
    guard let humidityFloat = dailyWeatherDictionary["humidity"] as? Double else { humidity = nil ; return }
    humidity = Int(humidityFloat * 100)
    guard let precipFloat = dailyWeatherDictionary["precipProbability"] as? Double else { precipChance = nil ; return }
    precipChance = Int(precipFloat * 100)
    summary = dailyWeatherDictionary["summary"] as? String
    guard let
        iconString = dailyWeatherDictionary["icon"] as? String,
        iconEnum = Icon(rawValue: iconString) else { icon = nil ; largeIcon = nil ; return }
    (icon, largeIcon) = iconEnum.toImage()

    guard let sunriseDate = dailyWeatherDictionary["sunriseTime"] as? Double else { sunriseTime = nil ; return }
    sunriseTime = timeStringFromUnixTime(sunriseDate)
    guard let sunsetDate = dailyWeatherDictionary["sunsetTime"] as? Double else { sunsetTime = nil ; return }
    sunsetTime = timeStringFromUnixTime(sunsetDate)
    guard let time = dailyWeatherDictionary["time"] as? Double else { day = nil ; return }
    day = dayStringFromUnixTime(time)

}


func timeStringFromUnixTime(unixTime: Double) -> String {

    let date = NSDate(timeIntervalSince1970: unixTime)

    dateFormatter.dateFormat = "hh:mm a"
    return dateFormatter.stringFromDate(date)

}

func dayStringFromUnixTime(unixTime: Double) -> String {

    let date = NSDate(timeIntervalSince1970: unixTime)
    dateFormatter.locale = NSLocale(localeIdentifier: NSLocale.currentLocale().localeIdentifier)
    dateFormatter.dateFormat = "EEEE"
    return dateFormatter.stringFromDate(date)

  }
}
1

There are 1 best solutions below

0
On

let's have

struct S {
    var i: Int?
    init(b: Bool){
        guard b == false else { return }
        //if b == true { return }
        i = 0 // if b == true, this statement doesn't execute
    }
}

let s1 = S(b: true)
let s2 = S(b: false)
print(s1, s2) // S(i: nil) S(i: Optional(0))

because var i: Int? has a default value nil, even though i = 0 is not reachable if parameter of init is true, the compiler doesn't complain.

struct S {
    let i: Int?
    init(b: Bool){
        guard b == false else { return }
        //if b == true { return }
        i = 0 // if b == true, this statement doesn't execute
    }
}

will NOT compile, with error: return from initializer without initializing all stored properties and note: 'self.i' not initialized, because constant let i: Int? doesn't have any default value

Your trouble is, that you return from init. Normally, avoid return from an initializer if your initializer is not fail-able / init? /. In case of fail-able init? the only accepted return value is nil.