Search code examples
swiftswift5

Get Values from JSON According to Condition


I have a local Json file in app bundle.

Existing Json file:

[
    {
        "id": 1001,
        "key1": true,
        "key2": "key2Value",
    },
    {
        "id": 1002,
        "key1": false,
        "key2": "key2Value",
    },
    {
        "id": 1003,
        "key1": true,
        "key2": "key2Value",
    },
]

I want to loop over the json and get the ids if key1 value is true.

I tried like this but I got error:

let vehicleInfoTest: [Vehicle] = readJSONTest("vehicleInfo.json")
func readJSONTest<T: Codable>(_ named: String) -> T{
    let data: Data
    let ids: Int
    do {
        let fileURL = try FileManager.default
            .url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: false)
            .appendingPathComponent("vehicleInfo.json")

        data = try Data(contentsOf: fileURL)
        
        // I can successfully get the foo
        let foo = try JSONDecoder().decode(T.self, from: data)
        
        // For loop gives an error: For-in loop requires 'Vehicle' to conform to 'Sequence'
        for item in foo as! Vehicle{
            if item.key1 == true{
                    ids = item.id
                }
        }
        return foo
    } catch {
        fatalError("Couldn't find  in main bundle.")
    }
}

Finally ids should be like this:

ids = 1001, 1003

How can I get the ids?


Solution

  • Your code is a bit of a mess, you have a generic function that you try to use as a non-generic function and you have also some other messy stuff in it. Since you first need to call the generic function as step 1 and then do the filtering of the result in a second step the following code will give you the Id's where key1 is true

    let vehicleInfoTest: [Vehicle] = readJSONTest("vehicleInfo.json")
    let idValues = vehicleInfoTest.filter({ $0.key1 }).map( {$0.id })
    

    Now to get this to work the function needs to be cleaned up

    func readJSONTest<T: Codable>(_ named: String) -> T{
        do {
            let fileURL = try FileManager.default
                .url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: false)
                .appendingPathComponent(named). //use parameter, not hardcoded string
    
            let data = try Data(contentsOf: fileURL)
            return try JSONDecoder().decode(T.self, from: data) // directly return decoded values
        } catch {
            fatalError("Decoding failed with error \(error)") // More useful error message
        }
    }