Swift 向下转型失败

Swift downcasting fails

我遇到了非常奇怪的行为,我真的无法理解它的正反面。我正在尝试将 class 类型存储在数组中并想稍后调用,但它不起作用。这是我的代码

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).

}

我特别疑惑

Could not cast value of type 'Test.Foo' (0x1085f17f0) to 'Test.Foo' (0x1085f1830)

错误。我如何通过向下转换为 BaseClass 来引用数组中的 classes 我可以使用它的 getDetails 函数

嗯...奇特。这个

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 测试总是失败的警告(预期,因为内容该数组不是 类 的 实例 ,而是它们的 类型 ).

The Swift Programming Language 指南的 为类型转换 定义 Class 层次结构部分中,我们发现

Swift’s type checker is able to deduce that Movie and Song have a common superclass of MediaItem, and so it infers a type of [MediaItem] for the library array:

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]

看起来你在做类似的事情,所以人们希望它能工作,但你不是 - 你存储的是 类 的类型,而不是它们的实例。

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

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

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

var w = arr[0] as! Foo

您正在尝试将 Class 类型转换为 class 类型的对象。此操作是不可能的,但您尝试使用 !这将导致您的崩溃。

要了解其他向下转换不起作用的原因,请在您的 playgroung 中试试这个:

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

我怀疑您使用的是 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
}

那是行不通的(并且您会收到警告)。 class 不是实例。

let w = arr[0] as! Foo

这将按预期崩溃,因为 class 不是实例。

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