Il y a un protocole:
protocol Valuable {
func value() -> Int
}
et une classe qui implémente le protocole:
class Value: Valuable {
private let v: Int
init(value: Int) {
v = value
}
func value() -> Int {
return v
}
}
Il existe un tableau d'objets Value stockés dans une variable de type Any:
let any: Any = [Value(value: 1), Value(value: 2), Value(value: 3)]
Il est possible de convertir n'importe quel élément en [Valeur]:
let arrayOfValue = any as? [Value] // [1, 2, 3]
Pourquoi n'est-il pas possible de valider Any to [Valuable]?
let arrayOfValuable = any as! [Valuable] // compiler error BAD INSTRUCTION
let arrayOfValuable2 = any as? [Valuable] // nil
Mise à jour: Dans Swift3, il est tout à fait possible de convertir [Any]
en [Valuable]
. La distribution réussira tant que tous les éléments du tableau pourront être convertis; la distribution échouera sinon.
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...
Auparavant, à compter de Swift 2: Pour créer un [Valuable]
à partir d'un [Any]
, vous devez le faire manuellement avec des fonctions telles que map
, comme d'autres réponses l'ont expliqué.
Il n'y a actuellement pas de covariance ni contravariance avec des génériques dans Swift (à compter de Swift 2). Cela signifie que des tableaux de types différents, tels que [String]
ou [UIView]
, ne peuvent pas être convertis les uns dans les autres, ni leurs types comparés.
[UIView]
et [UIButton]
n'ont aucune hiérarchie entre eux, même si UIButton
est une sous-classe de UIView
. C'est pourquoi même si ce qui suit retourne true:
Valuable.self is Any.Type // true
les distributions suivantes génèrent des erreurs pour la même raison:
var anyArray: [Any] = ["cadena"]
anyArray as! [String] // BAD_INSTRUCTION error
"some string" as! Double // BAD_INSTRUCTION error
Les deux classes ne portent aucune relation et la distribution est impossible, car le as!
est une distribution forcée, ce qui provoque une erreur.
Je fais un peu de Dig et vous devez ajouter l'attribut @objc comme suit
@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}]
Pour plus d'informations et pour obtenir une réponse à "pourquoi?": https://stackoverflow.com/a/25589323/989631
J'espère que ceci vous aidera.
De plus, cela ne fonctionne que si vous utilisez AnyObject au lieu de Any :(
Ça marche pour moi:
let arrayOfValuable = arrayOfValue?.map { $0 as Valuable }
ou le même:
let arrayOfValuable2 = (any as? [Value])?.map { $0 as Valuable }
En conclusion, arrayOfValuable
devrait avoir le type de [Valuable]?
Modifier:
Ou essayez ceci:
let arrayOfAny: [Any] = [Value(value: 1), Value(value: 2), Value(value: 3)]
let arrayOfValuable3 = arrayOfAny.map { $0 as Valuable }
Bien sûr, le meilleur moyen de le faire est de déclarer arrayOfAny
en tant que [Valuable]
, afin que vous n'ayez plus de problèmes par la suite.
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"
Conclusion:
Parfois, il est utile de convertir un type de tableau en un autre. La meilleure approche consiste généralement à ne pas convertir le type de tableau, mais à effectuer une vérification d'instance avant de compresser le tableau ou une vérification d'instance après le décompression du tableau