Swift 在斯威夫特中失败的演员有哪些?礼节
仅供参考:此处提出了Swift错误:Swift 在斯威夫特中失败的演员有哪些?礼节,swift,casting,Swift,Casting,仅供参考:此处提出了Swift错误: 我遇到了一个奇怪的问题,cast不起作用,但是控制台显示它是正确的类型 我有一个公共协议 public protocol MyProtocol { } 我在一个模块中实现了这一点,使用一个公共方法返回一个实例 internal struct MyStruct: MyProtocol { } public func make() -> MyProtocol { return MyStruct() } 然后,在我的视图控制器中,我触发一个以该对象作
我遇到了一个奇怪的问题,cast不起作用,但是控制台显示它是正确的类型 我有一个公共协议
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:)
方法中
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "Bob" {
if let instance = sender as? MyProtocol {
print("Yay")
}
}
}
但是,实例对MyProtocol的强制转换总是返回nil
当我运行po sender as时!MyProtocol
在控制台中,它给我一个错误无法将类型为“\u SwiftValue”(0x1107c4c70)的值转换为“MyProtocol”(0x1107c51c8)
。但是,po发送方
将输出一个有效的Module.MyStruct
实例
internal struct MyStruct: MyProtocol { }
public func make() -> MyProtocol { return MyStruct() }
为什么这个演员不工作
(我已经设法通过将协议装箱到结构中来解决它,但我想知道它为什么不能按原样工作,以及是否有更好的方法来修复它)问题是
发送方必须通过Objective-C世界,但Objective-C不知道这个协议/结构关系,因为Swift协议和Swift结构都是不可见的。使用类而不是结构:
protocol MyProtocol {}
class MyClass: MyProtocol { }
func make() -> MyProtocol { return MyClass() }
现在一切都如您所期望的那样工作,因为发送者可以在Objective-C世界中连贯地生活和呼吸。这是一个非常奇怪的错误——它看起来像是当一个实例被装入一个\u SwiftValue
中并被静态输入为Any(?)
而桥接到Obj-C时发生的。然后,该实例不能强制转换为它所符合的给定协议
根据Joe Groff在评论中的观点:
这是一个常见的“运行时动态强制转换在必要时不会桥接到协议”错误的实例。由于发送方被视为\u 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
进行强制转换,然后对协议进行强制转换似乎是可行的:
print(val as AnyObject as! P) // S()
因此,似乎静态地将其键入为AnyObject
也会使Swift检查桥接类型的协议一致性,从而使强制转换成功。正如乔·格罗夫(Joe Groff)在另一篇评论中所解释的,其原因是:
运行时有很多错误,它只尝试将某些转换到一个深度级别,但在执行其他转换之后就不尝试了(因此AnyObject->bridge->Protocol可以工作,但是Any->AnyObject->bridge->Protocol不能工作)。无论如何,它应该起作用
这是我的解决办法。我不想把它变成一个类
(re:),因为我的协议是由多个库实现的,它们都必须记住这样做
我将我的协议装箱到一个结构中
public struct BoxedMyProtocol: MyProtocol {
private let boxed: MyProtocol
// Just forward methods in MyProtocol onto the boxed value
public func myProtocolMethod(someInput: String) -> String {
return self.boxed.myProtocolMethod(someInput)
}
}
现在,我只传递BoxedMyProtocol的实例。仍然没有修复。到目前为止,我最喜欢和最简单的解决方法是链式铸造:
if let instance = sender as AnyObject as? MyProtocol {
}
只是在这里冒险,但是将这里的内部声明internal struct MyStruct:MyProtocol{}
更改为public
会改变什么吗?@Dennis Nope:(我并不是说你所隔离的行为是正确的。结构正在装箱,但你会认为它与协议的关系会继续存在。你可能想用bugs.swift.org
来提交一个bug。我已经使用协议P扩展了数组,但这个转换不适用于这种情况。这是一篇关于su的优秀文章每一个奇怪的错误。感谢链式铸造提示,我甚至不知道这是有效的代码!