Boon
Boon

Reputation: 41480

Storing different types of value in Array in Swift

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]

Upvotes: 17

Views: 35382

Answers (7)

Wes Chua
Wes Chua

Reputation: 1086

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]

Upvotes: 0

MoD
MoD

Reputation: 634

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
        }
}

Upvotes: 2

Abhishek Gupta
Abhishek Gupta

Reputation: 601

In Swift 3 you can use :

var testArray = ["a",true,3,"b"] as [Any]

Upvotes: 2

Bryan Chen
Bryan Chen

Reputation: 46598

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'

Upvotes: 22

Gordon Vanderbilt
Gordon Vanderbilt

Reputation: 369

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

Upvotes: 9

Martin Gordon
Martin Gordon

Reputation: 36389

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'.

Upvotes: 2

GoZoner
GoZoner

Reputation: 70145

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

Upvotes: 1

Related Questions