accessing nested dictionary from api in swift

Holy cow…there MUST be a better way to access formatted in

floorplan_summary: {
    bedrooms: {
        low: 1,
        high: 2,
        formatted: "1 - 2 Beds"
    }
}

than doing this:

  • Limit the amount of results returned in CloudKit
  • iOS 9 - “attempt to delete and reload the same index path”
  • Dynamic Height Issue for UITableView Cells (Swift)
  • How do I make my ^^ operator work with Double and Int?
  • Clamping camera around the background of a scene in SpriteKit
  • How to get cookie from a NSURLSession with Swift?
  •     if data["floorplan_summary"]?["bedrooms"] != nil {
            let bedrooms = data["floorplan_summary"]?["bedrooms"] as NSDictionary
            if bedrooms["formatted"] != nil{
                self.beds = bedrooms["formatted"] as String
            }
        }
    

    I want to just do this:

    self.beds = data["floorplan_summary"]?["bedrooms"]?["formatted"] as String
    

    ..but at each level the object seems to be cast as AnyObject. Why can the compiler assume this data["floorplan_summary"]?["bedrooms"] but not the above?

    How can I simplify this?

    3 Solutions Collect From Internet About “accessing nested dictionary from api in swift”

    Assuming data is NSDictionary, or [String:AnyObject]. You can:

    let beds = data["floorplan_summary"]?["bedrooms"]??["formatted"] as? String // -> as String?
                                                      ^
    

    You need extra ? because data["floorplan_summary"]?["bedrooms"] returns AnyObject??. You have to unwrap it twice.

    Why it returns AnyObject??? Because data["floorplan_summary"]? is AnyObject, and AnyObject may or may not have subscript. So, the first ? means, “If it has subscript“, and the second means “If subscript returns non nil“.

    If you are wanting the syntax you described, I’d suggest using SwiftyJSON. It seems pretty popular, and it’s all implemented in a single swift file so not hard to add it to your project. It would look something like this.

    let floorPlanSummary = JSON(data: yourRawData)
    self.beds = floorPlanSummery["bedrooms"]["formatted"].string
    

    You may be able to just invoke data.valueForKeyPath("floorplan_summary.bedrooms.formatted")