2

I am creating simple Json Parser that works like that: I have JsonData class that contains Anyobject as data. When I use jsonData["key"] it returns JsonData to i can chain jsonData["key"]["key2"] etc.

My question is how can I implement that class so i could cast it to lets say String:

jsonData["key"] as String without using some workarouds like

jsonData["key"].data as String

Code:

   class JsonData:CustomStringConvertible{
    let data:AnyObject

        var description: String{
        get{
            return "\(data)"
        }
    }
    init(_ data: Data) {
        self.data = try! JSONSerialization.jsonObject(with: data, options: []) as! [[String:AnyObject]]
    }

    init(_ data: AnyObject)    {
        self.data = data
    }

    subscript(key:String) -> JsonData{
        let newData = data as! [String:AnyObject]
        let test = newData[key]!
        return JsonData(test)
    }
    subscript(index:Int) ->JsonData{
        let newData = data[index]!
        return JsonData(newData)
    }

}
Ivan Genchev
  • 2,746
  • 14
  • 25
Jarosław Krajewski
  • 520
  • 1
  • 7
  • 18
  • You should really look into [SwiftyJson](https://github.com/SwiftyJSON/SwiftyJSON) – Sulthan Jul 18 '16 at 16:28
  • @Sulthan Agreed. I usually find it wildly overkill (I think people really overestimate how hard it is to write simple parsing code in most cases), but if you have really complicated and dynamic JSON structures, it is a nice tool for building the parser. But you should still get everything into structs for use outside the network stack. – Rob Napier Jul 18 '16 at 16:32
  • 1
    @RobNapier I completely agree. I don't understand why people work all the time with nested unparsed dictionaries. It's like working in Javascript. – Sulthan Jul 18 '16 at 16:53

1 Answers1

0

In order to do this, you'd add another overload, but it won't work like you're thinking.

subscript(key: String) -> String {
    let newData = data as! [String:AnyObject]
    return newData[key] as! String
}

So then jsonData["key"] as String works, but jsonData["key"]["key2"] is ambiguous and you'd have to write it (jsonData["key"] as JsonData)["key2"] which probably isn't what you want.

The short answer to this is don't do this. If you need this much access to JSON, you're probably storing your data incorrectly. Parse it to structs as quickly as you can, and then work with structs. Convert the structs back to JSON when you want that. Extensive work with AnyObject is going to break your brain and the compiler over and over again. AnyObject is a necessary evil, not an every day tool. Soon you will encounter that terrible day that you have an AnyObject? and the compiler just breaks down in tears. Well, at least it isn't Any.

Putting that aside, the better solution is to use labeled-subscripts.

subscript(string key: String) -> String {
    let newData = data as! [String:AnyObject]
    return newData[key] as! String
}

Now you can access that as json[string: "key"] rather than json["key"] as String.

Rob Napier
  • 286,113
  • 34
  • 456
  • 610