how to parse json data from local files?

2019-07-26 13:12发布

问题:

i am very new to json parsing and tried to parse a json file which has list of cars but when i do parse, it gives out nil

    func jsonTwo(){
    let url = Bundle.main.url(forResource: "car_list", withExtension: "json")!
    let data = try! Data(contentsOf: url)
    let JSON = try! JSONSerialization.jsonObject(with: data, options: []) as? [String : Any]
    print(".........." , JSON , ".......")
    let brand = JSON?["models"] as? [[String : Any]]
    print("=======",brand,"=======")
}

and when i made some modifications to this code as below

    func jsonTwo(){
    let url = Bundle.main.url(forResource: "car_list", withExtension: "json")!
    let data = try! Data(contentsOf: url)
    let JSON = try! JSONSerialization.jsonObject(with: data, options: []) 
    print(".........." , JSON , ".......")
    let brand = JSON["brand"] as? [[String : Any]]
    print("=======",brand,"=======")
}

then i get and error saying "Type 'Any' has no subscript members"

below is a sample of the json file that i am using

[{"brand": "Aston Martin", "models": ["DB11","Rapide","Vanquish","Vantage"]}]

回答1:

Please note that variable JSON in your code is an array of objects. You have to cast it properly.

func jsonTwo(){
    let url = Bundle.main.url(forResource: "car_list", withExtension: "json")!
    let data = try! Data(contentsOf: url)
    let JSON = try! JSONSerialization.jsonObject(with: data, options: []) 
    print(".........." , JSON , ".......")
    if let jsonArray = JSON as? [[String: Any]] {
        for item in jsonArray {
            let brand = item["brand"] as? String ?? "No Brand" //A default value
            print("=======",brand,"=======")
        }
    }
}


回答2:

The outer object is an array, please note the [] and the value for key models is a String array.

func jsonTwo() {
    let url = Bundle.main.url(forResource: "car_list", withExtension: "json")!
    let data = try! Data(contentsOf: url)
    let json = try! JSONSerialization.jsonObject(with: data) as! [[String : Any]]
    print(".........." , JSON , ".......")
    for item in json {
        let brand = item["brand"] as! String
        let models = item["models"] as! [String]
        print("=======",brand, models,"=======") 
    }
}

or more comfortable with Decodable

struct Car: Decodable {
    let brand : String
    let models : [String]
}

func jsonTwo() {
    let url = Bundle.main.url(forResource: "car_list", withExtension: "json")!
    let data = try! Data(contentsOf: url)
    let cars = try! JSONDecoder().decode([Car].self, from: data)
    for car in cars {
        let brand = car.brand
        let models = car.models
        print("=======",brand, models,"=======") 
    }
}

Normally you are strongly discouraged from force unwrapping optionals with ! but in this case the code must not crash because a file in the application bundle is read-only at runtime and any crash would reveal a design mistake.



回答3:

You need

struct Root: Codable {
    let brand: String
    let models: [String]
} 

do {

     let url = Bundle.main.url(forResource: "car_list", withExtension: "json")!
     let data = try Data(contentsOf: url) 
     let res = try JSONDecoder().decode([Root].self, from: data)
     print(res)

}
catch { 
    print(error)
}

Your problem as

let JSON = try! JSONSerialization.jsonObject(with: data, options: []) 

returns Any , so you can't use subscript it like a dictionary here JSON["brand"]