Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/jsf-2/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Swift 在斯威夫特中失败的演员有哪些?礼节_Swift_Casting - Fatal编程技术网

Swift 在斯威夫特中失败的演员有哪些?礼节

Swift 在斯威夫特中失败的演员有哪些?礼节,swift,casting,Swift,Casting,仅供参考:此处提出了Swift错误: 我遇到了一个奇怪的问题,cast不起作用,但是控制台显示它是正确的类型 我有一个公共协议 public protocol MyProtocol { } 我在一个模块中实现了这一点,使用一个公共方法返回一个实例 internal struct MyStruct: MyProtocol { } public func make() -> MyProtocol { return MyStruct() } 然后,在我的视图控制器中,我触发一个以该对象作

仅供参考:此处提出了Swift错误:


我遇到了一个奇怪的问题,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的优秀文章每一个奇怪的错误。感谢链式铸造提示,我甚至不知道这是有效的代码!