In the former version, to get a float value from a [String: Any]
dictionary, I can use let float = dict["somekey"] as? Float
, but in swift4.1, it doesn't work. It seems the type of dict["somekey"]
has been implicitly inferred as Double
before I get it, so casting from Double
to Float
always fails. I wonder if it is a new characteristic or just a bug.
--Here is the update.
I re-downloadeded an Xcode9.2 and did some experiments, now I think I figure out what's going on. Here is the test code:
let dict: [String : Any] = ["key": 0.1]
if let float: Float = dict["key"] as? Float {
print(float)
} else {
print("nil")
}
let dict1: [String : Any] = ["key": NSNumber(value: 0.2)]
if let float: Float = dict1["key"] as? Float {
print(float)
} else {
print("nil")
}
let number = NSNumber(value: 0.3)
if let float: Float = number as? Float {
print(float)
} else {
print("nil")
}
let number1 = NSNumber(floatLiteral: 0.4)
if let float = number1 as? Float {
print(float)
} else {
print("nil")
}
Running this code in Playground of Swift4 and Swift4.1, the results are different. In Swift4, the results are nil
0.2
0.3
0.4
, and In Swift4.1 the results are nil
nil
nil
nil
. From the result, I can learn two points:
1. When we convert JSON data into a [String : Any] dictionary
with the JSONSerialization
class, the numeric value is saved as an NSNumber
object, but not Int
, Double
or Float
.
2. In Swift4, we can use let float = NSNumberOjbect as? Float
to get a Float
value, but in Swift4.1 we can't. But still, we can get Int
or Double
value in this way, either in Swift4 or Swift4.1.
Finally again, is this a new feature or a bug? If someone knows, can you guys show up the announcement link?
Use Double , Float , CGFloat to convert floating-point values (real numbers). let lessPrecisePI = Float("3.14") let morePrecisePI = Double("3.1415926536") let width = CGFloat(Double("200.0")!)
Downcasting is the opposite of upcasting, and it refers to casting an object of a parent class type to an object of its children class. Downcasting is used to reconvert objects of a children class that were upcasted earlier to generalize. Let's say you own two cars and three trucks.
If the String contains a valid floating point value, then Swift will assign it to the floatValue constant which will be available within the if let scope. The result of this example will be printed as “Float value = 12.2416”.
You need to distinguish two cases (in Swift 3, it was three cases):
Any
containing a Swift native Double
Any
containing an NSNumber
(In Swift 3, there was type preserving NSNumber
case other than the normal NSNumber
.)
When you create a native Swift Dictionary
such as [String: Any]
, and set Double
value in a normal way like this in your update:
let dict: [String : Any] = ["key": 0.1]
In this case, Any
holds the metadata representing Double
and the raw value 0.1
as Double
.
And casting Any
holding Double
to Float
always fails. As Double
to Float
cannot be converted with as
-castings.
let dblValue: Double = 0.1
if let fltValue = dblValue as? Float { //<-Cast from 'Double' to unrelated type 'Float' always fails
print(fltValue)
} else {
print("Cannot convert to Float")
}
//->Cannot convert to Float
But, in case of Any
holding NSNumber
, as always happens when the Array
or Dictionary
is bridged from NSArray
or NSDictionary
, the behaviors are different between former Swifts and Swift 4.1.
The result of JSONSerialization
matches this case.
In former Swifts, (normal) NSNumber
to Float
was an always-success operation.
And in Swift 4.1, the behavior has changed with the new feature which I have shown in my comment:
SE-0170 NSNumber bridging and Numeric types
I omit the third case once found in Swift 3, it's past.
But it is very important how you get your Dictionary
or Array
, and how you set the value to them, to solve the issue Any
to Float
.
Finally again, is this a new feature or a bug? If someone knows, can you guys show up the announcement link?
This is a new feature, not a bug. See the link above, and related threads below.
Unable to bridge NSNumber to Float Swift 3.3
Unexpected behavior when casting an NSNumber to Float
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With