Erik Fritts Erik Fritts - 2 months ago 12
JSON Question

Subscripting problems since updating to Swift3

Our server side developer likes to give me JSON strings that have dictionaries of arrays of dictionaries of arrays of dictionaries. It's really pleasant.... So I've always serialized them into a dict[String:AnyObject] and had no trouble simply casting the objects as I pulled them out. :( Not today! I fixed all the other errors that popped up when I converted but this one doesn't make sense to me and I looked at similar questions and their code doesn't reflect my situation. I have only been doing this for 2 years so maybe I am just using bad practice and someone could break me of a bad habit. either way I would appreciate some help.

Here is a little snippet of one of my parsing functions I'll give you more if you need it.

func parseRecipes()
{
if self.avarhub.jsonDICT["recipes"]!.count > 0
{
for index in 0..<self.avarhub.jsonDICT["recipes"]!.count
{
self.avarhub.recipe.append(self.avarhub.jsonDICT["recipes"]![index]["recipe"] as! String) //the errors all happen on these lines
//they say ambiguous reference to member 'subscript' or Type 'Any' has no subscript members
}
}
self.tableviewrecipe.reloadData()
}


Thanks again for your help.

More code maybe this will help?

//data struscture my variable hub
internal struct varhub
{
//json dictionary
var jsonDICT = [String:AnyObject]()
var screenstatus = ""
var location = ""
var recipe = [String]()
var selectedrecipe = ""
}


//this function turns JSON string into a dictionary
func jsonStringToDict(_ text: String) -> [String:AnyObject]?
{
let data = text.data(using: String.Encoding.utf8)
do {
return try JSONSerialization.jsonObject(with: data!, options: []) as? [String:AnyObject]
}
catch _ as NSError
{
print("error")
}
return nil
}

Answer

In Swift 3 the compiler needs to know the types of all intermediate objects in consecutive key or index subscriptions to prevent runtime errors.

The solution is to tell the compiler that the value of the key recipes is an array of dictionaries.

This does the same as your method but without the ugly C-style loop and the empty check which is redundant.

func parseRecipes()
{
    for recipeItem in self.avarhub.jsonDICT["recipes"] as! [[String:Any]] {
        self.avarhub.recipe.append(recipeItem["recipe"] as! String)
    }
    self.tableviewrecipe.reloadData()
}

PS: AnyObject has been changed to Any in a lot of API, you might adjust your code, too.

Comments