Swift:将Any转换为协议对象数组

时间:2015-09-30 08:47:36

标签: swift casting protocols

有一个协议:

protocol Valuable {
    func value() -> Int
}

和实现协议的类:

class Value: Valuable {
    private let v: Int

    init(value: Int) {
        v = value
    }

    func value() -> Int {
        return v
    }
}

有一个Value对象数组存储在Any类型的变量中:

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

4 个答案:

答案 0 :(得分:6)

更新:在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中没有covariance nor contravariance泛型(从Swift 2开始)。这意味着不同类型的数组(如[String][UIView])不能相互转换,也不能比较它们的类型。

无论[UIView][UIButton]的子类,

UIButtonUIView之间都不存在层次结构。这就是为什么即使以下内容返回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!是强迫演员,它会引发错误。

答案 1 :(得分:3)

我做了一些挖掘,你必须添加@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

希望这会对你有所帮助。

修改

另外,只有在使用AnyObject而不是Any:(

答案 2 :(得分:2)

它对我有用:

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],这样您就不会遇到任何问题。

答案 3 :(得分:0)

将数组[任意]转换为数组[字符串]

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"

<强>结论:
有时它可以从一种数组类型转换为另一种数组类型。在大多数情况下,最好的方法是不转换数组类型,而是在打包数组之前进行实例检查或在解压缩数组后进行实例检查