プロトコルがあります:
protocol Valuable {
func value() -> Int
}
プロトコルを実装するクラス:
class Value: Valuable {
private let v: Int
init(value: Int) {
v = value
}
func value() -> Int {
return v
}
}
Any型の変数に格納されたValueオブジェクトの配列があります。
let any: Any = [Value(value: 1), Value(value: 2), Value(value: 3)]
Anyを[Value]にキャストできます:
let arrayOfValue = any as? [Value] // [1, 2, 3]
Anyを[Valuable]にケース分けできないのはなぜですか?
let arrayOfValuable = any as! [Valuable] // compiler error BAD INSTRUCTION
let arrayOfValuable2 = any as? [Valuable] // nil
更新:Swift3では、[Any]
を[Valuable]
にキャストすることが完全に可能です。配列内のすべての要素をキャストできる限り、キャストは成功します。そうでなければキャストは失敗します。
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...
以前はSwift 2:現在[Valuable]
を[Any]
から作成するには、map
などの関数を使用して手動で行う必要があります。
現在、= 共分散または反変 はありませんSwift(Swift 2現在)のジェネリックです。これは、異なるタイプの配列が[String]
や[UIView]
のように、互いにキャストしたり、型を比較したりすることはできません。
UIButton
がUIView
のサブクラスであるかどうかに関係なく、[UIView]
と[UIButton]
は相互に階層を持ちません。これが、以下がtrueを返す場合でも、その理由です。
Valuable.self is Any.Type // true
次のキャストは、同じ理由でエラーを生成します。
var anyArray: [Any] = ["cadena"]
anyArray as! [String] // BAD_INSTRUCTION error
"some string" as! Double // BAD_INSTRUCTION error
as!
は強制キャストであるためエラーが発生するため、2つのクラスには関係がなく、キャストは不可能です。
私はいくつかのDigを行い、次のように@objc属性を追加する必要があります
@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}]
詳細と「なぜ?」のアンサーを取得するには: https://stackoverflow.com/a/25589323/989631
これがお役に立てば幸いです。
さらに、Any :(の代わりにAnyObjectを使用する場合にのみ機能します。
わたしにはできる:
let arrayOfValuable = arrayOfValue?.map { $0 as Valuable }
または同じ:
let arrayOfValuable2 = (any as? [Value])?.map { $0 as Valuable }
結論として、arrayOfValuable
のタイプは[Valuable]?
である必要があります
編集:
またはこれを試してください:
let arrayOfAny: [Any] = [Value(value: 1), Value(value: 2), Value(value: 3)]
let arrayOfValuable3 = arrayOfAny.map { $0 as Valuable }
確かに、そのためのより良い方法は、arrayOfAny
を[Valuable]
として宣言することです。これにより、後で問題が発生することはありません。
let arrayOfAny:Array<Any> = [1,"2",3.0,CGFloat(4)]
let stringArray:Array<String> = arrayOfAny.map {String($0)}
print(stringArray)//"1", "2", "3.0","4.0"
結論:
1つの配列型から別の配列型に変換すると便利な場合があります。最善の方法は、ほとんどの場合、配列タイプを変換せず、配列をパックする前にインスタンスチェックを実行するか、配列をアンパックした後にインスタンスチェックを実行することです。