Is Float, Double, Int an Anyobject

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)

Sample Image

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 and AnyObject 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 ids 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 Ints, Strings, and Doubles 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



Leave a reply



Submit