user3591436
user3591436

Reputation: 161

Swift parse JSON formatting

I created an API that has a JSON response in the following format:

[{"name":"xxx","direct_link":"http:\/\/domain.com\/images\/xxx.png","image":"http:\/\/domain.com\/images\/xxx.png"},{"name":"yyy","direct_link":"http:\/\/domain.com\/images\/yyy.png","image":"http:\/\/domain.com\/images\/yyy.png"}]

Notice how the JSON response has no array title.

My Swift code looks like this:

       do {
            //converting resonse to NSDictionary
            var teamJSON: NSDictionary!
            teamJSON =  try NSJSONSerialization.JSONObjectWithData(data!, options: .MutableContainers) as? NSDictionary


            //getting the JSON array teams from the response
            let teams: NSArray = teamJSON["teams"] as! NSArray


            //looping through all the json objects in the array teams
            for i in 0 ..< teams.count{

                //getting the data at each index
                let teamId:Int = teams[i]["name"] as! String!
                let teamName:String = teams[i]["direct_link"] as! String!
                let teamMember:Int = teams[i]["image"] as! Int!

                //displaying the data
                print("name -> ", teamId)
                print("direct_link -> ", teamName)
                print("image -> ", teamMember)
                print("===================")
                print("")

            }

Notice how the array is looking for a title "teams". How can I ensure the JSON is properly parsed and displays the 3 values I need for the JSON response? I'm new to app coding and have a web background, still trying to wrap my head around this.

As it stands when I try to build and run I get the following error: fatal error unexpectedly found nil while unwrapping an optional value

Upvotes: 1

Views: 159

Answers (3)

gunjot singh
gunjot singh

Reputation: 2598

ISSUE:

Your NSJSONSerialization.JSONObjectWithData would return an NSArray and not NSDictionary

SOLUTION:

Update code as below:

var teamJSON =  try NSJSONSerialization.JSONObjectWithData(data!, options: .MutableContainers) as? NSArray

//getting the JSON array teams from the response

let teams: NSArray = teamJSON

ALSO

Don't force cast values using !

Always cast it as optional using ?

Upvotes: 0

Alexander
Alexander

Reputation: 63271

Try this:

do {
    guard let teams = try NSJSONSerialization.JSONObjectWithData(data!, options: .MutableContainers) as? NSArray else {
        //Doesn't exist, or isn't an NSArray
        return
    }

    for team in teams {
        //getting the data at each index
        let teamId = team["name"] as! String
        let teamName = team["direct_link"] as! String
        let teamMember = team["image"] as! Int

        //displaying the data
        print("name -> ", teamId)
        print("direct_link -> ", teamName)
        print("image -> ", teamMember)
        print("===================")
        print()
    }
}
//...

Some notes:

  1. Don't cast to implicitly unwrapped optionals (e.g. String!)
  2. Don't add unnecessary type annotations
  3. Use guard let to enforce preconditions (e.g. the JSON isn't nil, and is castable to NSArray).
  4. Prefer iterating over elements of an Array (for team in teams) over iterating a range (for i in 0..<teams.count)
    • If you need only the indices, use for i in teams.indices
    • If you need the indices and elements, use for (index, team) in teams.enumerate()

Upvotes: 1

Daniel Hall
Daniel Hall

Reputation: 13679

The problem is this line:

teamJSON =  try NSJSONSerialization.JSONObjectWithData(data!, options: .MutableContainers) as? NSDictionary

because you are trying to cast a JSON array to a dictionary.

Just use

teamJSON =  try NSJSONSerialization.JSONObjectWithData(data!, options: .MutableContainers) as? NSArray

And then you also won't need to do this:

//getting the JSON array teams from the response
let teams: NSArray = teamJSON["teams"] as! NSArray

Because teamJSON is already the array.

I think the key issue you have to be aware of is that NSJSONSerialization.JSONObjectWithData() can return either an NSDictionary OR an NSArray, depending on whether the root level data in the JSON is an array or a dictionary.

Upvotes: 1

Related Questions