Michael Johnston
Michael Johnston

Reputation: 5330

How to decode JSON value that can be String or NSNumber?

An API I am consuming sometimes returns:

... total: "40" ...

and sometimes:

... total: 40 ...

Is there a clean way to write a guard/let statement that will extract an int value regardless of whether the parsed json object is an NSString or an NSNumber?

NOTE: I'm looking for the answer how to decode the value, not a reference to a library that allows me to punt on solving it. I already know about SwiftyJSON etc.

Upvotes: 1

Views: 1190

Answers (3)

vadian
vadian

Reputation: 285260

A different approach

let jsonDict : [String : CustomStringConvertible] = ["foo" : 40, "bar" : "50" ]
for (_, value) in jsonDict {
  print(Int("\(value)")!)
}

Upvotes: 0

Martin R
Martin R

Reputation: 540065

You could use the fact that you can call any method on AnyObject via optional chaining. Example:

let jsonDict : [String : AnyObject] = ["foo" : 40, "bar" : "50" ]

if let val = jsonDict["foo"]?.integerValue 
{
    print(val) // 40
}

if let val = jsonDict["bar"]?.integerValue 
{
    print(val) // 50
}

If the value for the key does not exist, or does not respond to integerValue, the result is nil and the optional binding fails. Otherwise, the integer value is assigned to val.

Upvotes: 1

Michael Johnston
Michael Johnston

Reputation: 5330

I realized that I could define a protocol specifying the integerValue getter and empty protocol extensions to NSString and NSNumber, and then cast the value to that protocol:

protocol HasNumber {
  var integerValue: Int { get }
}
extension NSString:HasNumber{}
extension NSNumber:HasNumber{}

and then:

guard let total = (json["total"] as? HasNumber)?.integerValue else { }

Upvotes: 0

Related Questions