Benjamin Lowry
Benjamin Lowry

Reputation: 3789

JSON Serialization not working properly

I've been learning the basics of JSON and I am trying to read data from a JSON file that I have written. The JSON file looks like this:

gradeBoundaries = {
    "Subjects": [ 
        {
        "Title":"Biology HL", 
        "Boundaries": 
            {
            1:[0,15],
            2:[16,27],
            3:[28,39],
            4:[40,52],
            5:[53,64],
            6:[65,77],
            7:[78,100]
            }
        }   

    ]
}

The code that I am using to take the data from this file is as follows:

if let url = Bundle.main.url(forResource: "gradeBoundaries", withExtension: "json") {
        do {

            let jsonData = try Data(contentsOf: url)
            do {

                let jsonResult: [([String: String], [String: [Int : [Int]]] )]  = try JSONSerialization.jsonObject(with: jsonData, options: JSONSerialization.ReadingOptions.mutableContainers) as! [([String: String], [String: [Int : [Int]]] )]  //the entire object

            } catch {}
        } catch {}
    }

When I run the code above, everything works fine until this line:

let jsonResult: [([String: String], [String: [Int : [Int]]] )]  = try JSONSerialization.jsonObject(with: jsonData, options: JSONSerialization.ReadingOptions.mutableContainers) as! [([String: String], [String: [Int : [Int]]] )]  //the entire object

As you can see I am trying to cast jsonResult as a fairly complicated data structure. I have tried many others including NSDictionary and Array but none of them seem to make a difference. Since I am so new to JSON I could just be misinterpreting the format of the data, and if anyone could point me in the right direction that would be great.

However, it is indeed nothing to do with the casting, then I am even more lost. This is the way that many SO answers have said to read the data, but it simply does not work for me.

I even tried switching between Data and NSData to no effect. I want to be able to break this data down into smaller pieces, but my program keeps on getting stuck on this line, so I need some help. Thanks!

EDIT

Editing the data type to Any did not allow the line to execute:

let jsonResult: Any  = try JSONSerialization.jsonObject(with: jsonData, options: JSONSerialization.ReadingOptions.mutableContainers) as! Any

EDIT: 31 Dec 2016

Trying to make it work as below was ineffective:

typealias JSONDictionary = [String: Any]

    if let url = Bundle.main.url(forResource: "gradeBoundaries", withExtension: "json") {
        do {

            let jsonData = try Data(contentsOf: url)

            if let jsonResult: JSONDictionary = try JSONSerialization.jsonObject(with: jsonData, options: []) as? JSONDictionary {

                print("success!")

            }
        } catch {}
    }

However, it seems like a really good idea, so I think there must be something seriously wrong about my JSON or I'm doing something really stupid in my code.

EDIT

The JSON that I have been using is apparently invalid. I modified it now to be this:

{
    "Subjects": [ 
        {
        "Title":"Biology HL", 
        "Boundaries": 
            {
            1:[0,15],
            2:[16,27],
            3:[28,39],
            4:[40,52],
            5:[53,64],
            6:[65,77],
            7:[78,100]
            }
        }   

    ]
}

Upvotes: 0

Views: 2658

Answers (2)

Benjamin Lowry
Benjamin Lowry

Reputation: 3789

So I figured it out and feel like an idiot. After using Java and Swift for the longest time, I thought I would leave some comments on my JSON.

The JSON I was actually using was this:

{
"Subjects": [//[([String: String], [String: [Int : [Int]]] )] 
    {
    "Title":"Biology HL", //[String: String]
    "Boundaries": //[String: [Int: [Int]]]
        {
        "1":[0,15], //[Int: [Int]]
        "2":[16,27],
        "3":[28,39],
        "4":[40,52],
        "5":[53,64],
        "6":[65,77],
        "7":[78,100]
        }
    }   

]
}

However, I thought that I would leave the comments out of the SO question because they weren't necessary.

After copying @vadian's suggested JSON my code worked. I then came up with this hypothesis and tried adding a comment to his JSON, and needless to say it didn't work.

So I guess the moral of this story is read up about commenting on code before you actually do it.

Upvotes: 0

vadian
vadian

Reputation: 285079

First of all a message to all writers of online tutorials:

Please stop suggesting the reading option .mutableContainers in Swift. It's completely meaningless because mutability is provided for free by assigning the object to a variable.


Don't confuse yourself by annotating that weird snake-type.

To understand the structure read the hierarchy. [] is an array, {} a dictionary.

For convenience declare a type alias for a JSON dictionary

typealias JSONDictionary = [String:Any]

Then walk through the JSON (assuming the root object is a dictionary):

do {
    if let jsonResult = try JSONSerialization.jsonObject(with:jsonData, options: []) as? JSONDictionary {
        if let subjects = jsonResult["Subjects"] as? [JSONDictionary] {
            for subject in subjects {
                print(subject["Title"] as? String)
                if let boundaries = subject["Boundaries"] as? JSONDictionary {
                    for (key, value) in boundaries {
                        print(key, value)
                    }
                }
            }
        }
    }
} catch {
    print(error)
}

Regarding the JSON the keys in the Boundary dictionary must be strings:

{
    "Subjects": [
        {
        "Title":"Biology HL",
        "Boundaries":
            {
            "1":[0,15],
            "2":[16,27],
            "3":[28,39],
            "4":[40,52],
            "5":[53,64],
            "6":[65,77],
            "7":[78,100]
            }
        }
    ]
}

Upvotes: 1

Related Questions