There is a protocol:
protocol Valuable {
func value() -> Int
}
and a class which implements the protocol:
class Value: Valuable {
private let v: Int
init(value: Int) {
v = value
}
func value() -> Int {
return v
}
}
There is an array of Value objects stored in a variable of Any type:
let any: Any = [Value(value: 1), Value(value: 2), Value(value: 3)]
It is possible to cast Any to [Value]:
let arrayOfValue = any as? [Value] // [1, 2, 3]
Why it is not possible to case Any to [Valuable]?
let arrayOfValuable = any as! [Valuable] // compiler error BAD INSTRUCTION
let arrayOfValuable2 = any as? [Valuable] // nil
Updated: In Swift3 it is entirely possible to cast [Any]
to a [Valuable]
. The cast will succeed as long as all the elements in the array can be casted; the cast will fail otherwise.
var strings: [Any] = ["cadena"]
var mixed: [Any] = ["cadena", 12]
strings as! [String] // ["cadena"]
mixed as? [String] // nil
mixed as! [String] // Error! Could not cast value...
Previously as of Swift 2: To make a [Valuable]
out of an [Any]
it must be done manually with functions like map
as other answers have explained.
There is currently no covariance nor contravariance with generics in Swift (as of Swift 2). This means that arrays of different types, like [String]
or [UIView]
, cannot be casted into each other, nor their types compared.
[UIView]
and [UIButton]
bear no hierarchy between each other regardless that UIButton
is a subclass of UIView
. This is why even if the following returns true:
Valuable.self is Any.Type // true
the following casts yield errors for the same reason:
var anyArray: [Any] = ["cadena"]
anyArray as! [String] // BAD_INSTRUCTION error
"some string" as! Double // BAD_INSTRUCTION error
The two clases bear no relation and the cast is impossible, since the as!
is a forced cast it booms the error.
I do some dig and you have to add @objc attribute as follows
@objc
protocol Valuable {
func value() -> Int
}
class Value: Valuable {
private let v: Int
init(value: Int) {
v = value
}
@objc func value() -> Int {
return v
}
}
let any: AnyObject = [Value(value: 1), Value(value: 2), Value(value: 3)]
let arrayOfValueable = any as! [Valuable] // [{v 1}, {v 2}, {v 3}]
For more info and to get anwser for "why?": https://stackoverflow.com/a/25589323/989631
Hope this will help you.
Plus it works only if you use AnyObject instead of Any :(
It works for me:
let arrayOfValuable = arrayOfValue?.map { $0 as Valuable }
or the same:
let arrayOfValuable2 = (any as? [Value])?.map { $0 as Valuable }
In conclusion, arrayOfValuable
should have the type of [Valuable]?
Edit:
Or try this:
let arrayOfAny: [Any] = [Value(value: 1), Value(value: 2), Value(value: 3)]
let arrayOfValuable3 = arrayOfAny.map { $0 as Valuable }
Sure, better way to do that is to declare arrayOfAny
as [Valuable]
, so you'll have no problems afterwards.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With