仅供参考:在此处引发的Swift错误:https : //bugs.swift.org/browse/SR-3871
我遇到一个奇怪的问题,即强制转换不起作用,但控制台将其显示为正确的类型。
我有公开协议
public protocol MyProtocol { }
然后,我使用一个返回实例的公共方法在一个模块中实现此功能。
internal struct MyStruct: MyProtocol { } public func make() -> MyProtocol { return MyStruct() }
然后,在我的视图控制器中,我以该对象作为发送者触发segue
let myStruct = make() self.performSegue(withIdentifier: "Bob", sender: myStruct)
到目前为止一切都很好。
问题出在我的prepare(for:sender:)方法上。
prepare(for:sender:)
override func prepare(for segue: UIStoryboardSegue, sender: Any?) { if segue.identifier == "Bob" { if let instance = sender as? MyProtocol { print("Yay") } } }
但是,将实例强制转换为MyProtocol始终返回nil。
nil
当我po sender as! MyProtocol在控制台中运行时,它给了我错误Could not cast value of type '_SwiftValue' (0x1107c4c70) to 'MyProtocol' (0x1107c51c8)。但是,po sender将输出一个有效的Module.MyStruct实例。
po sender as! MyProtocol
Could not cast value of type '_SwiftValue' (0x1107c4c70) to 'MyProtocol' (0x1107c51c8)
po sender
Module.MyStruct
为什么这种转换不起作用?
(我已经设法通过将协议包装在结构中来解决它,但是我想知道为什么它不能按原样工作,以及是否有更好的方法来修复它)
这是一个非常奇怪的错误-看起来好像是通过将一个实例放入a _SwiftValue并将其静态键入为,将实例桥接到Obj- C时发生的Any(?)。然后,该实例不能转换为它所遵循的给定协议。
_SwiftValue
Any(?)
根据Joe Groff在您提交的错误报告的评论中所说:
这是一般“运行时动态转换在需要桥接到协议时不桥接”错误的一个实例。由于发件人被视为_SwiftValue对象类型,并且我们试图获取不符合它的协议,因此我们在不尝试桥接类型的情况下放弃了。
一个更简单的示例是:
protocol P {} struct S : P {} let s = S() let val : Any = s as AnyObject // bridge to Obj-C as a _SwiftValue. print(val as? P) // nil
足够奇怪的是,首先强制AnyObject转换为协议,然后强制转换为协议,似乎可以正常工作:
AnyObject
print(val as AnyObject as! P) // S()
因此看来,静态键入它AnyObject使Swift也会检查桥接类型的协议一致性,从而使转换成功。正如Joe Groff在另一条评论中所述,这样做的原因是:
运行时存在许多错误,它们仅尝试将某些转换转换到一个深度级别,而在执行其他转换后则不行(因此AnyObject-> bridge-> Protocol可能起作用,但是Any-> AnyObject-> bridge-> Protocol不起作用’)。它 应该 无论如何都可以工作。