I'm not looking for an answer like how to do it correctly but why this happens.
Here is the code:
func isInt(param: AnyObject?) {
if let value = param as? Int {
print(value)
} else {
print("Not Int")
}
if let value = param {
if value is Int {
print(value)
} else {
print("Not Int")
}
}
}
let a:AnyObject? = 1.2
let b:Float? = 1.2
let c:Double? = 1.2
isInt(a)
isInt(b)
isInt(c)
I understand in the first if
loop, the param
is casted to Int
and then print out 1
.
But why in second if
loop, if value is Int
is true and then print out 1.2
?
In your b
case, let value = param
bridges value
to an NSNumber
type. For NSNumber
, value is Int
will always be true.
For unbridged values:
a is Int // always true, AnyObject bridges to NSNumber here
b is Int // false, cast from Float to Int always fails
c is Int // false, cast from Double to Int always fails
This answer assumes Foundation has been imported. Without Foundation, your assignments will fail.
Take a look at https://developer.apple.com/library/ios/documentation/Swift/Conceptual/BuildingCocoaApps/WorkingWithCocoaDataTypes.html, specifically:
Instances of the Swift numeric structure types, such as Int, UInt, Float, Double, and Bool, cannot be represented by the AnyObject type, because AnyObject only represents instances of a class type. However, when bridging to Foundation is enabled, Swift numeric values can be assigned to constants and variables of AnyObject type as bridged instances of the NSNumber class.
We can see this in action in a Playground:
let value = 1.2
value.dynamicType //Double.Type
value is Int //false
let castValue = value as AnyObject
castValue.dynamicType //__NSCFNumber.Type (a private framework class, part of the NSNumber class cluster)
//NSNumber is bridged to Int, UInt, Float, Double, and Bool so `is` tests for those types will return `true`
castValue is Int //true
castValue is Float //true
//NSNumber is not bridged to String so an `is` test will return `false`
castValue is String //false
well, it seems that it if you do the following:
func isInt(param: AnyObject?) {
if let value = param {
if value is Double {
print("I'm a double")
}
if value is Int{
print("I'm an int")
}else {
print("Not Int")
}
}
}
it will print "I'm a double" for all three and "I'm an int" for all three as well. It seems that when it goes to the if statement it bridges value to NSNumber, which will be true for any NSNumber type.
However, let's say you do the following:
if let value = param {
if value is String {
print("I'm a String")
}
if value is Int{
print("I'm an int")
}else {
print("Not Int")
}
}
}
since String is not of type NSNumber, it will skip and go to the if value is Int, which is of type NSNumber and return the value.