Amey
Amey

Reputation: 252

Converting JSON String to Dictionary<String, Any> serializes Boolean as Int

I am trying to serialize Json string into a dictionary And it is converting the boolean value to a int value. check out the code.

Check the output value for key "BoolArgument" its returning 1 instead of true

Note: I can not convert the string to a swift data object using Codable as the keys in the json dictionary are not constants.

========================
Code
========================

let inputArgumentsString = "{\"FloatArgument\":1.0,\"BoolArgument\":true,\"ObjectArgument\":{}}"

var toJson: Dictionary<String, Any>? {
     guard let data = self.data(using: .utf8) else { return nil }
     do {
         return try JSONSerialization.jsonObject(with: data, options : .allowFragments) as? Dictionary<String, Any>
     } catch let error {
         print(error.localizedDescription)
         return nil
     }
 }

print(self.inputArgumentsString?.toJson)```

========================
Output
========================

po self.inputArgumentsString?.toJson
▿ Optional<Dictionary<String, Any>>
  ▿ some : 3 elements
    ▿ 0 : 2 elements
      - key : "BoolArgument"
      - value : 1
    ▿ 1 : 2 elements
      - key : "ObjectArgument"
      - value : 0 elements
    ▿ 2 : 2 elements
      - key : "FloatArgument"
      - value : 1

Upvotes: 0

Views: 773

Answers (2)

arkus
arkus

Reputation: 437

This is just a debugger description of the result.

For Bool it uses NSNumber with values 1 as true and 0 as false.

If you call in your code something like:

guard let json = self.inputArgumentsString?.toJson,
        let boolean = json["BoolArgument"] as? Bool
        else { return }

print(boolean)

It will print true or false.


If you want to check if the value is a boolean or not, you could try using something like this:

for key, value in json {
  if let number = value as? NSNumber {
    let numberType = CFNumberGetType(number as CFNumberRef)

    switch numberType {
      case .charType:
        //Bool
        print(key, value as? Bool)
      case .sInt8Type, .sInt16Type, .sInt32Type, .sInt64Type, .shortType, .intType, .longType, .longLongType, .cfIndexType, .nsIntegerType:
        //Int
        print(key, value as? Int)
      case .float32Type, .float64Type, .floatType, .doubleType, .cgFloatType:
        //Double
        print(key, value as? Double)
    }
  }
}

Upvotes: 2

Jon Shier
Jon Shier

Reputation: 12770

Internally, JSONSerialization is an Objective-C class that uses NSNumber instances to represent both numeric and boolean values from JSON. When you print the dictionary, these instances have their numeric values printed. However, NSNumber knows when it's storing a boolean value, so it will automatically be bridged when you trying to access the value. toJSON["BoolArgument"] as? Bool should give the correct value.

In any event, using Codable to properly parse your types might be a better solution.

Upvotes: 1

Related Questions