14

Get this error:

Fatal error: Unable to bridge NSNumber to Float. What is the problem?

enter image description here

enter image description here

This is the original message, it is float and not string.

{\"name\":\"Tomas\",\"gender\":\"male\",\"probability\":0.99,\"count\":594}

enter image description here

Jean-Baptiste Yunès
  • 34,548
  • 4
  • 48
  • 69
János
  • 32,867
  • 38
  • 193
  • 353
  • No, it is float in the original JSON. – János Apr 02 '18 at 11:55
  • 1
    The error is showing that the returning value is a NSNumber and you can not cast it to float. So Try this: "d.value(forKey:"probability")!.floatValue" – Y_Y Apr 02 '18 at 11:57
  • Does one of the casting methods from [this post](https://stackoverflow.com/a/27279483/3397217) work for you? (It's for `Double` but they work the same.) – LinusGeffarth Apr 02 '18 at 11:58
  • 1
    Why are you even messing with dictionary representations? Wouldn't conforming to `Decodable` make this much easier? – Gereon Apr 02 '18 at 11:59

4 Answers4

33

You have many different types of numbers in Swift/Foundation. Your NSKeyValueCoding has been set as instance of NSNumber (see excerpt of JSON serialization documentation below) so you need to read as is, and then ask to convert this NSNumber as Float if needed:

if let n = d.value(forKey: "probability") as? NSNumber {
    let f = n.floatValue
}

JSONSerialization documentation says:

A Foundation object that may be converted to JSON must have the following properties:

  • The top level object is an NSArray or NSDictionary.
  • All objects are instances of NSString, NSNumber, NSArray, NSDictionary, or NSNull.
  • All dictionary keys are instances of NSString.
  • Numbers are not NaN or infinity.
Jean-Baptiste Yunès
  • 34,548
  • 4
  • 48
  • 69
0

You are using the wrong API.

Don’t use KVC (valueForKey) unless you really need KVC.

For getting a dictionary value use always key subscription (or objectForKey)

if let probability = d["probability"] as? Float {
    print(probability)
}
vadian
  • 274,689
  • 30
  • 353
  • 361
0

I would recommend ditching the dictionary representation entirely and moving to a type-safe parser using Decodable:

struct User: Decodable {
    let name: String
    let gender: String
    let probability: Float
    let count: Int
}

let str = "{ \"name\": \"Tomas\", \"gender\": \"male\", \"probability\":0.99, \"count\": 594 }"
let data = str.data(using: .utf8)!
do {
  let user = try JSONDecoder().decode(User.self, from: data)
} catch {
  // handle errors
}
Gereon
  • 17,258
  • 4
  • 42
  • 73
-1

Some inside baseball here:

When swift is casting a floating point number from json to float, it has some kind of validation that makes sure the number lands on a terminating fractional value that the float data type can support.

E.g. if your value was 0.25 (1/4th), 0.875 (7/8ths), etc., it would not give you an error.

If your value does not fall on one of these terminating fractions (e.g. 0.33), it assumes some data could be lost to the lack of precision, and it throws an error.

If you don't care about the potential data loss, here is one way to convert the value to a float without much worry:

Float(jsonDictionary["jsonDictionaryKey"] as! Double)
smakus
  • 1,107
  • 10
  • 11