16

In Swift Programming Language, it says "An array stores multiple values of the same type in an ordered list." But I have found that you can store multiple types of values in the array. Is the description incorrect?

e.g.

var test = ["a", "b", true, "hi", 1]
Boon
  • 40,656
  • 60
  • 209
  • 315

7 Answers7

22

From REPL

 xcrun swift
  1> import Foundation
  2> var test = ["a", "b", true, "hi", 1]
test: __NSArrayI = @"5 objects" {
  [0] = "a"
  [1] = "b"
  [2] =
  [3] = "hi"
  [4] = (long)1
}
  3>

you can see test is NSArray, which is kind of AnyObject[] or NSObject[]

What happening is that Foundation provides the ability to convert number and boolean into NSNumber. Compiler will perform the conversion whenever required to make code compile.

So they now have common type of NSObject and therefore inferred as NSArray


Your code doesn't compile in REPL without import Foundation.

 var test = ["a", "b", true, "hi", 1]
<REPL>:1:12: error: cannot convert the expression's type 'Array' to type 'ArrayLiteralConvertible'

 var test:Array = ["a", "b", true, "hi", 1]
<REPL>:4:18: error: cannot convert the expression's type 'Array' to type 'ExtendedGraphemeClusterLiteralConvertible'

but you can do this

var test : Any[] = ["a", "b", true, "hi", 1]

Because they have a common type, which is Any.


Note: AnyObject[] won't work without import Foundation.

var test:AnyObject[] = ["a", "b", true, "hi", 1]
<REPL>:2:24: error: type 'Bool' does not conform to protocol 'AnyObject'
bearMountain
  • 3,950
  • 1
  • 36
  • 44
Bryan Chen
  • 45,816
  • 18
  • 112
  • 143
  • AnyObject is the type – juniperi Jun 16 '14 at 04:05
  • Is there a way to verify the inferred type of an array? – Boon Jun 16 '14 at 04:06
  • Bryan, I have fixed the code error. Adding Array does it. – Boon Jun 16 '14 at 04:10
  • @Boon easiest way is type it in REPL – Bryan Chen Jun 16 '14 at 04:13
  • var test = ["a", "b", true, "hi", 1] compiles fine in playground – juniperi Jun 16 '14 at 04:13
  • REPL has been unstable for me. Bryan, any idea why without the type compiler can't infer that it's an array? – Boon Jun 16 '14 at 04:14
  • @juniperi this means either REPL or playground have a bug... not sure which one is correct – Bryan Chen Jun 16 '14 at 04:14
  • var test = ["a", "b", true, "hi", 1] compiles fine in Xcode 6 as well. – Boon Jun 16 '14 at 04:15
  • Thanks Bryan, REPL works good and provides insight to things. Looks like if you declare an Array type, it's AnyObject[], if you don't, it's NSArrayI. – Boon Jun 16 '14 at 04:27
  • Swift have lots "magic" about type inference. Things can convert to other types automatically without notice (like C++ constructor without `explicit` keyword). you can even [convert string literal to CGPoint](http://stackoverflow.com/a/24161109/642626) – Bryan Chen Jun 16 '14 at 04:32
  • Just to note, there is a lot of confusion around `Any` vs. `AnyObject`. From Apple : https://developer.apple.com/library/prerelease/ios/documentation/swift/conceptual/swift_programming_language/TypeCasting.html -> under "Type Casting for Any and AnyObject". – bauerMusic Jun 16 '14 at 05:43
  • 4
    @BryanChen: maybe this Any[] is now [Any] –  Jul 03 '16 at 14:32
  • Try it on Terminal and PlayGround, prove that we need `var test = ["a", "b", true, "hi", 1] as [Any]`, otherwise the compiler will complain. – Zhou Haibo Jul 18 '21 at 06:12
9

To initialize an Array with arbitrary types, just use var arbitraryArray = [Any]().

2

AnyObject is a type and you can create an array that holds those, which (as the class name implies) means it can hold any type of object. NSArrays aren't type-bound and when you create an array with mixed types, it will generate an NSArray instead of an Array. I wouldn't rely on this, however, since it could change in the future (AnyObject[] is automatically bridged with NSArray).

You can try this in a playground (note: dynamicType returns "(Metatype)" and I wasn't sure how to pull out the actually type so I relied on the compiler error):

var x = [ 1, 2, "a" ]
x.dynamicType.description() // -> __NSArrayI

var y = [ 1, 2 ]
y.dynamicType.description() // -> Error: Array<Int>.Type does not have a member named 'description'.

var z: AnyObject[] = [ 1, 2, "a" ]
z.dynamicType.description() // -> Error: Array<AnyObject>.Type does not have a member named 'description'.
Martin Gordon
  • 36,329
  • 7
  • 58
  • 54
2

In Swift 3 you can use :

var testArray = ["a",true,3,"b"] as [Any]
Abhishek Gupta
  • 601
  • 5
  • 16
2

Instead you can also use a struct in your class:

struct Something {
        let a: String
        let b: String?
        let boolValue: Bool
        let value: Int

        init(a: String, b: String? = nil, boolValue: Bool, value: Int) {
            self.a = a
            self.b = b
            self.boolValue = boolValue
            self.value = value
        }
}
MoD
  • 564
  • 4
  • 14
1

The description is correct, an Array stores multiple values of the same type. The key is that one value has multiple types. That is, for example, a String has types of String and Any; an instance of a class Ellipse : Shape has types of Ellipse, Shape, AnyObject and Any.

 14> class Foo {}
 15> class Bar : Foo {}
 16> var ar1 : Array<Any> = [1, "abc", Foo(), Bar()]
ar1: Any[] = size=4 {
  [0] = <read memory from 0x7fa68a4e67b0 failed (0 of 8 bytes read)>
  [1] = { ... }
  [2] = {}
  [3] = { ... }
}
 17> ar1[0]
$R5: Int = <read memory from 0x7fa68a51e3c0 failed (0 of 8 bytes read)>
 18> ar1[1]
$R6: String = { ... }
 19> ar1[2]
$R7: Foo = {}
 20> ar1[3]
$R8: Bar = {
  lldb_expr_14.Foo = {}
}
 21> ar1[0] as Int
$R9: Int = 1
GoZoner
  • 67,920
  • 20
  • 95
  • 145
0

Worked and Tested on Swift 5

You can explicitly state the data type to any. The Any type represents values of any type.

Type Casting

var test = ["a", "b", true, "hi", 1] as [Any]

Type explicit

var test: [Any] = ["a", "b", true, "hi", 1]
Swee Kwang
  • 724
  • 9
  • 15