迅速转发失败

时间:2015-04-21 13:48:52

标签: swift casting

我遇到了非常奇怪的行为,我真的无法做出正面或反面的行为。我试图在类数组中存储类类型,并希望稍后调用,但它不起作用。这是我的代码

class BaseClass {

    class func getDetails() -> String {
        return "aaaaaa"
    }
}

class Foo: BaseClass {

    override class func getDetails() ->String {
        return "foo"
    }
}


class Bar: BaseClass {
    override class func getDetails() ->String {
        return "bar"
    }
}

var arr = [Foo.self, Bar.self]
func test1 () {

    var x = Foo.self
    println(x.getDetails()) //prints foo
    if let y = arr[0] as? Foo.Type {
        println(y.getDetails()) //doesn't execute

    }
    if let z = arr[0] as? BaseClass.Type {
        println(z.getDetails()) //doesn't execute
    }
    if let t = arr[0] as? BaseClass {
        println(t.dynamicType.getDetails()) //doesn't execute
    }
    // lets crash
    var w = arr[0] as! Foo
    //Could not cast value of type 'Test.Foo' (0x1085f17f0) to 'Test.Foo' (0x1085f1830).

}

我特别困惑

  

无法转换类型' Test.Foo' (0x1085f17f0)到' Test.Foo'   (0x1085f1830)

错误。如何通过向下转换到BaseClass来引用数组中的类,以便我可以使用其getDetails函数

3 个答案:

答案 0 :(得分:1)

嗯......很特别。此

var arr = [Foo.self, Bar.self]
println(arr.count)
println(arr)

将打印2然后崩溃,但这样可以正常工作:

var arr: [BaseClass.Type] = [Foo.self, Bar.self]
println(arr.count)
println(arr)

除了稍后在代码中收到有关as? BaseClass.Type测试总是成功(因此,不需要)的警告,并且as? BaseClass测试总是失败(预期,因为数组的内容不是类的实例,而是类型)。

在{{3>}指南的定义类型转换的类层次结构部分中,我们找到了

  

Swift的类型检查器能够推断出Movie和Song有一个   MediaItem的常见超类,因此它推断出一种[MediaItem]   对于库数组:

let library = [
    Movie(name: "Casablanca", director: "Michael Curtiz"),
    Song(name: "Blue Suede Shoes", artist: "Elvis Presley"),
    Movie(name: "Citizen Kane", director: "Orson Welles"),
    Song(name: "The One And Only", artist: "Chesney Hawkes"),
    Song(name: "Never Gonna Give You Up", artist: "Rick Astley")
]
// the type of "library" is inferred to be [MediaItem]

看起来你正在做类似的事情,所以人们会期望它能够发挥作用,但你不会 - 你正在存储类的类型,而不是它们的实例。 / p>

答案 1 :(得分:0)

所以Foo.self等同于目标c的[Object class]。 所以在

var arr = [Foo.self, Bar.self]

你基本上是在创建一个类类型数组(不是基类BaseClass的对象--Foo,Bar)

开启

var w = arr[0] as! Foo

您正在尝试将Class类型强制转换为该类类型的对象。此操作是不可能的,但您尝试使用它来强制执行!这将导致你的崩溃。

要了解其他向下转换无效的原因,请在playgroung中尝试:

println("\(_stdlib_getDemangledTypeName(Foo.self))")
println("\(_stdlib_getDemangledTypeName(Foo.Type))")

答案 2 :(得分:0)

我怀疑你使用的是旧版Swift。我发现在6.3中,你需要为arr提供一个类型(我怀疑6.2正在解决这个问题,这可能是你问题的根源):

let arr: [BaseClass.Type] = [Foo.self, Bar.self]

让我们来看看其余的事情:

let x = Foo.self
println("x:" + x.getDetails()) //prints foo

是的;应该是预期的。

if let y = arr[0] as? Foo.Type {
    println("y" + y.getDetails()) //doesn't execute
}

我发现它确实在6.3中执行。也就是说,这是不必要的,因为BaseClass包含getDetails方法。以下也适用:

let y2 = arr[0]
println("y2:" + y2.getDetails())

下一步:

if let z = arr[0] as? BaseClass.Type {
    println("z:" + z.getDetails()) //doesn't execute
}

我发现它确实会执行,正如您所期望的那样,尽管这是不必要的。

if let t = arr[0] as? BaseClass {
    println(t.dynamicType.getDetails()) //doesn't execute
}

这不起作用(你得到警告)。一个类不是实例。

let w = arr[0] as! Foo

这会像预期的那样崩溃,因为一个类不是一个实例。

因此,如果您正确执行此操作,则不需要进行类型转换。你可以拥有一组类,并调用它们。也就是说,你应该总是在Swift中认真思考你是否真的需要一堂课。通常,更好的解决方案是结构和协议。