Is Float, Double, Int an AnyObject?
Because you have Foundation imported, Int
, Double
, and Float
get converted to NSNumber
when passed to a function taking an AnyObject
. Type String
gets converted to NSString
. This is done to make life easier when calling Cocoa and Cocoa Touch based interfaces. If you remove import UIKit
(or import Cocoa
for OS X), you will see:
error: argument type 'Int' does not conform to expected type 'AnyObject'
when you call
passAnyObject(a)
This implicit conversion of value types to objects is described here.
Update for Swift 3 (Xcode 8 beta 6):
Passing an Int
, Double
, String
, or Bool
to a parameter of type AnyObject
now results in an error such as Argument of type 'Int' does not conform to expected type 'AnyObject'.
With Swift 3, implicit type conversion has been removed. It is now necessary to cast Int
, Double
, String
and Bool
with as AnyObject
in order to pass it to a parameter of type AnyObject
:
let a = 1
passAnyObject(a as AnyObject)
Float value returns with double quotes from [String: AnyObject] in swift
Replace AnyObject with Any like below:
let appliedLoyalty: Float = 1.05
let appliedWallet: Float = 0.55
let custID = "puma"
let payLoad: [String: Any] = ["custid": custID, "discounts": ["loyalty": appliedLoyalty,"wallet": appliedWallet]] // custid is string value
print(payLoad)
Swift: AnyObject cast to Float failed
The 0.6
is a Double
literal value. As such, you can't cast it to Float
(you need to convert it).
Try this instead:
let f = Float(json["progress"] as! Double)
Or, if you aren't really sure what type of number this AnyObject
holds, the safer approach would be:
let f = (json["progress"] as! NSNumber).floatValue
Of course, those as!
above will crash hard if the json value is missing or you misjudge the expected type. Use the as?
operator instead if you feel otherwise :)
Casting crash course. When casting a known Double
value to a Float
, the compiler gives us a nice heads up about this:
let d = 0.6
let f = d as? Float
warning: cast from 'Double' to unrelated type 'Float' always fails
AnyObject and Any in Swift
AnyObject
is only for reference types (classes), Any
is for both value and reference types.
So you should go for [String: Any]
.
Type Casting for Any and AnyObject
Swift provides two special types for working with nonspecific types:
Any
can represent an instance of any type at all, including function
types.AnyObject
can represent an instance of any class type.
NOTE:
Use
Any
andAnyObject
only when you explicitly need the behavior and
capabilities they provide. It is always better to be specific about
the types you expect to work with in your code.
From The Swift Programming Language:
https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/TypeCasting.html#//apple_ref/doc/uid/TP40014097-CH22-ID342
-
Also note that when you work with Cocoa API, it's common to receive an Array of AnyObject, this is because Objective-C arrays are NOT typified.
So you need to cast them to the array type you expect.
-
EDIT: (december 22, 2015)
On the last statement, note that this is changing with Swift 2.0 and Xcode 7.
Apple has introduced ‘Lightweight’ generics in Objective-C so lots of Cocoa APIs now already returns the correct type.
EDIT: (october 18, 2016)
Note that, as of Swift 3.0, Objective-C id
s are now imported as Any
, not anymore as AnyObject
.
Type Casting For AnyObject to represent instances of any reference type
For your success case, there is some conversion going on behind the scenes.
Try adding this at the end of your appends to see what's happening:
for item in array {
print(item.dynamicType)
}
NSNumber vs Int, Float in Swift Dictionary
Primitive types like Float
, Int
, Double
are defined as struct
so they do not implement AnyObject
protocol. Instead, Any
can represent an instance of any type at all so your dictionary's type should be:
var dictionary: [String: Any] = [:]
Apart from that, in your code when you do:
dictionary["key"] = Float(1000) as AnyObject
Float
gets converted to NSNumber
implicitly and then is upcasted to AnyObject
. You could have just done as NSNumber
to avoid the latter.
Why is a Swift ArrayInt compatible with AnyObject?
If you import Foundation
(which you must be, because you reference NSCoder
) then [Int]
is implicitly bridged to NSArray
because Int
is implicitly bridged to NSNumber
. Int64
and your non-objc structs are not implicitly bridged to ObjC types, so arrays of those are not bridged to NSArray
.
Swift Downcasting AnyObject (Float) to String
You can simply use variable interpolation in a string with Swift. First get your price and then just use it in a string with the $ prepended-
var stockValueString=""
if let price=dataArray[0]["stockPrice"] {
stockValueString="$\(price)"
}
Also, note by (strong) convention variable should start with a lower-case letter. Class names start with a capital.
How to convert RealmOptional to Int or Float in Swift?
Lets assume your RealmOptional<Float>()
variable is named myFloat
. Then, use the getter for the RealmOptional:s (see this git entry for Realm) underlying value, .value
, rather then checking the RealmOptional itself:
var value = myFloat.value // value variable now of type Float
Below follows and explanation of why the AnyObject?
switches doesn't behave as you expect:
From Apples Language Guide - Type Casting:
Type Casting for Any and AnyObject
Swift provides two special type aliases for working with non-specific
types:
- AnyObject can represent an instance of any class type.
- Any can represent an instance of any type at all, including function types.
Hence, the AnyObject
type can can hold instances of any class type, but the fundamental numeric types (Int
, Double
etc) in Swift are not of class type, but of structure type.
In the switch
in your example, the AnyObject
instance is not inferred but cast to the first possible successful downcast, which will be whatever case
you put top-most that is of a numeric type. Hence, if you change the ordering of your case
:s in the switch, the casting will change.
let value: AnyObject? = 30.0
// try change the order
switch value {
case is String: print("string");
case is Float: print("float"); // hits `Float` downcast first -> prints float
case is Int: print("int");
default: print("other")
}
Now, you could, however, cast your AnyObject
to an NSNumber
(class instance), and continue from there. From Working with Cocoa Data Types documentation:
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.
Note however that NSNumber
is fundamentally different from the Swift numeric types (Int
, Double
etc) in that the former hold any kind of number, and allows us to cast this number to different type of numeric types. However, we cannot easily infer which type a specific NSNumber
instance should be cast to, but we could implement our own (not so pretty) specification as how to infer different NSNumber
to different swift fundamental numeric types.
However, before proceeding with NSNumber
hacking:
From above, the core problem is that your value
property is of type AnyObject?
. Could you please post the code that lead to value
being of type AnyObject?
. Possibly the casting to Int
, Float
and so on if not necessary if using the getter of the RealmOptional (hence no need to casting RealmOptional<T>()
to AnyObject?
?).
A double number's type is Int in Swift
Swift arrays can only hold one type. When you declared:
let arr = [1, "a", 2.88]
Swift made arr
of type [NSObject]
. You can verify this by Option-clicking on arr
to see its type. This only works because you have Foundation imported (your import UIKit
imports Foundation
as well). Try removing import UIKit
.
Then, the values 1
and 2.88
were converted to NSNumber
and "a"
to NSString
so that they can be stored in that [NSObject]
array because Int
s, String
s, and Double
s are not NSObjects
. NSNumber
and NSString
are subclasses of NSObject
. Swift picks the most restrictive type for the array. Had your array been [1, true, 2.88]
, the array type would have been [NSNumber]
.
The interesting thing about an NSNumber
is that it is an object container that wraps many different types. You can put an Int
in and take out a Double
. So, it is misleading then when you test it with is
. It responds "true" meaning, "I can be that if you want".
import Foundation
let n: NSNumber = 3.14
print(n is Int) // "true"
print(n is Double) // "true"
print(n is Bool) // "true"
print(n as! Int) // "3"
print(n as! Double) // "3.14"
print(n as! Bool) // "true"
Note: Had you declared your arr
to be [Any]
, then this would have worked as you expected:
let arr:[Any] = [1, "a", 2.88]
let last = arr.last
if last is Int {
print("The last is Int.")
} else {
print("The last is not Int.") // "The last is not Int."
}
But Swift is not going to create an array of type Any
for you unless you ask explicitly (because quite frankly it is an abomination in a strongly typed language). You should probably rethink your design if you find yourself using [Any]
.
The only reason Swift creates [NSObject]
when Foundation is imported is to make our lives easier when calling Cocoa and Cocoa Touch APIs. If such an API requires an NSArray
to be passed, you can send [1, "a", 2.88]
instead of [NSNumber(integer: 1), NSString(string: "a"), NSNumber(double: 2.88)]
.
Related Topics
iOS Notification When Application Is Closed
Xcode 7 Beta 6, Dyld _Nsarray0_ Crash
How to Default Uilabel Font and Size Using Swift
Objective C- Trouble Updating UI on Main Thread
Multiple Uialertcontrollers in iOS
How to Add a Custom Separator to Uitableviewcell
Initializing Swift Properties That Require "Self" as an Argument
Preventing Avcapturevideopreviewlayer from Rotating, But Allow UI Layer to Rotate with Orientation
How to Load Multiple Storyboard Files Depending on iOS Version? (5 and 6)
Swift- Custom Uitableviewcell Delegate to Uiviewcontroller Only One Protocol Works
iOS 13 Set Uisearchtextfield Placeholder Color
Creating a Custom Progress Bar with Images
Uialertview Is Not Working in Swift
iOS Web App: Showing Content Only If the Application Is Standalone