'check the json response is array or int or string for a key?

I am having the json response in which "products" key sometime having the int value and some cases it had an array? How to check whether it is having array or Int?

"products": 25

or

"products": [77,80,81,86]

I am using this

self.productsCount = mResp["products"] as! [Int]

but it is crashed every time when it is not having array.

Now i am not getting how to check this because i have the different option for Int and Array?

Please help me.Thanks



Solution 1:[1]

It crashes because you force unwrap as an Integer Array, even though you just have an integer. The solution is to check for both:

self.productsCount = mResp["products"] as? [Int] ?? mResp["products"] as? Int

Other Solution

if let proCount = mResp["products"] as? [Int] { 
  self.productsCount = proCount
} else {
  self.productsCount = mResp["products"] as? Int
}

Solution 2:[2]

This is temporary solution as you want. Check for possible type with "Any" type.

    var anyType : Any!
    anyType = "123"
    anyType = ["Test","Test1"]
    anyType = 1
    if anyType is Array {
        print("is Array")
    }else if anyType is String {
        print("is String")
    }else if anyType is Int {
        print("is Int")
    }

Solution 3:[3]

let dict = [77,80,81,86]//Pass your parameter or parsed json value
 if dict is Array<Any> {
    print("Yes, it's an Array")
}
else{
      print("NO, it's not an Array")

}

Solution 4:[4]

let's assume your json name is jsonData

Check for Int and Array Int:

if let intVal = jsonData["products"] as? Int {
    print("Products is a Integer: ", intVal)

} else if let jsonArr = jsonData["products"] as? [Int] {

    var intVals = [Int]()
    for json in jsonArr {
        intVals.append(json)
    }
    print("Json is array of Int: ", intVals)
}

Solution 5:[5]

Generic solution would be like this,

let products = mResp["products"] as? Any
if let item = products as? [Int] {
    print("array", item)
} else if let item = products as? Int {
    print("Integer", item)
}

Solution 6:[6]

Use Generics for obtaining a better solution and provide the type at the time of decoding this model.

struct Product<T: Codable>: Codable {
    let products: T?
}

And you can use it with nested try catch:

do {
    let product = try JSONDecoder().decode(Product<Int>.self, from: data)
    print(product)
} catch {
    do {
        let product = try JSONDecoder().decode(Product<[Int]>.self, from: data)
        print(product)
    } catch {
        print(error)
    }
}

Note: This solution assumes there is not more than a few different type-varying properties in the codable struct. If there are multiple type-varying properties I'd recommend use a custom init(decoder:) as provided in the accepted answer which would be much better design instead of having a try-catch tree.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2
Solution 3 Priya Bijawat
Solution 4
Solution 5 PPL
Solution 6 Frankenstein