0

I am filling a dict with values from json:

var dict = Dictionary<String, AnyObject>()

dict["venue"] =         json["info"]["venue"].string!
dict["addressStreet"] = json["info"]["addressStreet"].string!
dict["capacity"] =      json["info"]["capacity"].int!
dict["mascot"] =        json["info"]["mascot"].string!
dict["foodService"] =   json["info"]["foodService"].boolean!

Imagine the values from the json are:

//Smith Concert Hall (a string)
//1234 Main Street (a string)
//150 (a number)
//no mascot listed - a null value
//true for food service - a boolean value

In case it has a bearing on this question, I am using SwiftyJSON to access the items in json. Info on SwiftyJSON is here: https://github.com/SwiftyJSON/SwiftyJSON

So, in this example we are dealing with several different types, such as strings, ints, booleans, and the chance of null values.

The json I am working on doesn't just have 5 items like in the above example. It has many. So, for an efficient program, I have done the following:

for (indexCount, element) in enumerate(appDelegate.json["info"]){
    dict[element.0] = json["info"][element.0]
}

Which means instead of creating specific assignment statements for all possibilities, I am looping through and creating a tuple from each json item. The tuple contains the key and value. With that key and value I am automatically setting the key and value of the dict items.

BUT - when I go to use the dict item later, there is a problem. For example, if I try to do this, I get nil:

let a = dict["capacity"] as? String
println(a)  //results with: nil

let b = dict["capacity"]
println("\(b)")  //results with: nil

let c = String(stringInterpolationSegment: dict["capacity"])
println(c)  //results with: nil

So to recap: If I am filling an "String, AnyObject" dictionary by enumerating through a json array with different value types... what can I do on the front or back end of this process to avoid errors and have useful data? In particular, strings seem to work fine, but when I encounter an int and try to cast it as a string (I have tried several ways) it fails all together or returns nil.

Thank you.

Jack Amoratis
  • 613
  • 1
  • 6
  • 22

2 Answers2

0

The data held in a JSON object can be String, Bool, NSNumber, NSURL, ... and you are using only String, Int and Bool. The common supertype of these is Any. Declare your dict as Dictionary<String,Any>. (Every where you subsequently use your Any data you will be forced to type-cast to String, Bool, Int as appropriate for the 'tag')

But, I'd say, by using Any you are fighting the types. Swift is a strongly-typed, statically-typed programming language and you need to go with it by being explicit with your types. Get your generic input data, from JSON, into explicitly-typed abstractions, manipulate those abstractions, and then, if required, convert back to generic output data, to JSON.

class Event {
  var venue : String
  var addressStreet : String
  var capacity : Int
  var mascot : String
  var foodService : Bool
  // ... many more ...

  init (json:JSON) {
    self.venue = json["venue"].string!
    ...
  }
}

var event1 = Event(json["info"])

Of course, the above only works if the JSON data tags are static. If, rather, there really is no static structure to the data, then Dictionary<String,Any> is the best you can do and you'll need to deal with Any.

GoZoner
  • 59,252
  • 19
  • 87
  • 137
0

It turns out, when looping through JSON to add the items to a dictionary, you don't need to worry about their type. You can just add them just as they are: unchanged in their 'JSON' type to the array.

This question began with a loop through JSON results to add them to a dictionary:

var dict = Dictionary<String, AnyObject>()
for (indexCount, element) in enumerate(appDelegate.json["info"]){
    dict[element.0] = json["info"][element.0]
}

Now I see that the problem was that the array was defined as 'String, AnyObject'. But it turns out if we declare the array as:

var dict = Dictionary<String, JSON>()

(we changed AnyObject to JSON)...then we are able to add and retrieve the original JSON value. Then when we are about to use the value somewhere (such as putting string into a label, or getting an int to do a calculation) SwiftyJSON allows us to cast it with a subscript such as .string or .int.

Jack Amoratis
  • 613
  • 1
  • 6
  • 22