无法将类型“ A”的值强制转换为“ B”

时间:2019-06-18 22:46:23

标签: ios swift

因此,我试图解决在另一个问题(Fatal error: Use of unimplemented initializer 'init(...)' for class '__lldb_expr_1.B')中描述的问题,但随后又遇到了另一个问题。

我创建了一个测试项目来隔离问题。我有一个包含以下内容的A.swift文件:

class A {
    private let i: Int

    private init(i: Int) {
        self.i = i
    }
}

extension A {
    convenience init() {
        self.init(i: 0)
    }
}

然后在另一个文件中,我将B声明为A的子类。

class B: A { }

为了对此进行测试,我有一个简单的ViewController像这样:

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        let b: B = B()
        let a: A = b

        _ = a as! B
    }

}

这可以正常编译,但是当我运行它时,它在将a下转换为B时崩溃。这是我得到的错误:

Could not cast value of type 'MyTestProject.A' (0x1070bd570) to 
'MyTestProject.B' (0x1070bd4d8).

编辑: 仅当我在单独的文件中声明A和B时,才会出现此错误。如果在同一文件中声明它们,我将得到Fatal error: Use of unimplemented initializer 'init(...)' for class '__lldb_expr_1.B'中描述的错误。

1 个答案:

答案 0 :(得分:0)

这肯定是一个错误。确定错误是什么并不是一件容易的事。

作为测试,我对您的示例进行了一些修改。在此文件中,我们具有:

class A {
    private let i: Int
    private init(i: Int) {
        self.i = i
    }
    convenience init() {
        self.init(i: 0)
    }
}

在我们的viewDidLoad中:

let a: A = B()
print(type(of:a))

这使事情变得轻松简单。好吧,所以在另一个文件中

class B : A {}

那么,在我的测试中:

  • 在Release版本中,我们崩溃:“对类'B'使用未实现的初始值设定项'init(i :)'”(我确定您能识别一个)

  • 在Debug版本中,我们不会崩溃,但会打印A,这显然是错误的答案。

我可能会增加一些复杂性(我尝试了很多事情),但是我会添加这种观察结果:如果我们在private之前删除init一词,所有的问题都会消失。进行了这一更改,我们在调试或发行版中打印了B,并且不会崩溃。

因此,我将理论化认为该问题与在后台实现初始化程序继承规则的方式有关。他们似乎有能力在某些条件下打破多态性。 (我的测试使用了Xcode 11 beta 2,因此使用了Swift 5.1。)