0

I make some kind of JSON parsing with a weatherAPI. To prevent me of running into nullPointer (maybe the page is offline or something) I covered my parsing into a guard, because I thought he protect me for unwrapping optional value.

guard
     let loadedWeather = (json["weather"] as! [[String:AnyObject]])[0]["description"] as? String,
     let loadedTemperatur = (json["main"] as! [String:AnyObject])["temp"] as? Float,
     let loadedWindSpeed = (json["wind"] as! [String:AnyObject])["speed"] as? Float
else {
     print("Weather JSON-Parsing failed")
     return
}

Have I misunderstood the function of guard? If so, how can I solve that problem? Actually the page is offline or something and returns an error JSON page with other tags, so "weather", "main"...etc. not include. I hoped in that case my guard brings me inside my else statement so I can handle with that case.

Thanks a lot.

kuemme01
  • 472
  • 5
  • 19

3 Answers3

1

You are misusing the syntax for guard - use it as follows:

guard let weatherArray = json["weather"] as? [[String:AnyObject]], let mainDict = json["main"] as? [String:AnyObject], let windDict = json["wind"] as? [String:AnyObject] else {
    return
}
guard let dict = weatherArray.first else {
    return
}
 guard let description = dict["description"] as? String, let temp = mainDict["temp"] as? Float, let speed = windDict["speed"] as? Float else {
    return
}

Though I would recommend you follow the if let syntax as outlined by Damien.

Jacob King
  • 6,025
  • 4
  • 27
  • 45
0

You should look for conditional unwrapping : https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/TheBasics.html

if let weather = json["weather"] {
// weather is define here, you can use it
}
Damien
  • 3,322
  • 3
  • 19
  • 29
0

Change

 as! [[String:AnyObject]]

to

 as? [[String:AnyObject]]

You are trying to force cast your json data (as!) so even though you are using guard you will still get a crash at that spot if its nil.

Edit: You said its still forcing as! so maybe try to split up your code like so. Should also make it more readable and easier for you to get other info out of the dicts/arrays of the json response. Something like this should work

/// Get json data
guard
   let loadedWeather = json["weather"] as? [[String:AnyObject]],
   let loadedTemperatur = json["main"] as? [String:AnyObject],
   let loadedWindSpeed = json["wind"] as? [String:AnyObject]
   else {
     print("Weather JSON-Parsing failed")
     return
}

/// Get info from json data
guard 
   let weatherDescription = loadedWeather[0]["description"] as? String,
   let temperature = loadedTemperatur["temp"] as? Float,
   let windSpeed = loadedWindSpeed["speed"] as? Float
   else {
     print("Weather JSON-Parsing failed")
     return
}

 /// do something with weather description, temperature, windSpeed

Maybe even better try to split up those guard statements for each line separately so incase one fails your whole block doesn't exit. In that case better to use if let because you dont want to exit early. Just dont start any pyramids of doom with if let statements.

/// Weather
if let loadedWeather = json["weather"] as? [[String:AnyObject]],
   let weatherDescription = loadedWeather[0]["description"] as? String {
      // do something with weather description
}

/// Temperature
if let loadedTemperatur = json["main"] as? [String:AnyObject],
   let temperature = loadedTemperatur["temp"] as? Float {
     // do something with temperature
}

/// Wind speed
if let loadedWindSpeed = json["wind"] as? [String:AnyObject],
   let windSpeed = loadedWindSpeed["speed"] as? Float {
     // do something with windspeed
}

Hope this helps.

crashoverride777
  • 10,581
  • 2
  • 32
  • 56