任何不一致的铸造?在可选绑定期间进入 Swift 中的协议

Posted

技术标签:

【中文标题】任何不一致的铸造?在可选绑定期间进入 Swift 中的协议【英文标题】:Inconsistent Casting of Any? into a Protocol in Swift during Optional Binding 【发布时间】:2016-09-20 02:50:42 【问题描述】:

我在某些 Swift 可选绑定中遇到了问题,该绑定需要强制转换为协议。我在一个运行良好的操场上有以下代码。

protocol CodeCollection 
    var name: String  get 
    var codes: [String]  get 


struct VirtualDoors: CodeCollection 
    var name = "Virtual Doors"
    var codes: [String] = ["doorNumba1", "doorNumba2"]


// Instance of VirtualDoors
let doors = VirtualDoors()

// cast into Any? like what awake(withContext context: Any?) receives
var context = doors as Any?

print(context)
if let newDoors = context as? CodeCollection 
    // Works as expected
    print(newDoors)

我在 watchKit 中使用与 awake(withContext context: Any?) 中传递的一条信息完全相同的协议和结构,并且与 cast 的可选绑定在那里失败。

override func awake(withContext context: Any?) 
    super.awake(withContext: context)

    // Just checking to make sure the expected item is in fact being passed in
    print(context)
    // "Optional(VirtualDoors(name: "Virtual Doors", codes: ["doorNumba1", "doorNumba2"]))\n"

    if let newDoors = context as? CodeCollection 
        self.collection = newDoors
        print("Context Casting Success")
     else 
        // Casting always fails
        print("Context Casting Fail")
    

如果有人能告诉我为什么这在操场上有效,但在 watchKit 类方法中无效,我将不胜感激。

我觉得我错过了一些非常明显的东西。

【问题讨论】:

你有两个不同命名空间的 CodeCollection 定义吗? 我只有一个。只有协议具有该名称。我一直在尝试,如果我尝试转换为 struct VirtualDoor 类型,它工作正常,当然我不能使用这个视图来显示其他类型的集合。 其实也许是这样。该协议是在“共享”文件夹中监视套件扩展之外的文件夹中定义的。不过,我确实检查了 ios 应用程序和 watchKit Target 框。除此之外,我不确定您的意思或如何解决它。首先尝试制作一个在目标之间共享代码的应用程序。有什么建议吗? 如果它包含在两个目标中,那么我认为您将拥有两个具有相同名称但位于不同命名空间中的不同类。是否可以从其中一个目标中删除它? 是的,我能做到。它还没有真正在 iOS 中做任何事情。我应该指出,在我将它添加到两个目标之前,我遇到了这个问题,它最初只是在 watch kit 目标上。 【参考方案1】:

我怀疑你 doorscontext 是一个隐含的 Any??,它只会解开到另一个 Optional 而不是 CodeCollection

如果你在唤醒函数中使用let context = context as AnyObject,那么应该能够正确解包。

把它想象成一个你看不到的强制解包选项。

这个操场的最后两个 cmets 应该给其他人一个例子来玩,其中保留了可选项,但可选项类型被擦除和包装。

import Foundation

protocol Target 
    var name: String  get 


func takesAnyOptional(context: Any?) -> String? 
    return (context as? Target)?.name


struct Source: Target 
    let name = "Source"


let solid = Source()
print((solid as Target).name)
takesAnyOptional(context: solid)

let solid_any = solid as Any
print((solid_any as? Target)?.name)
takesAnyOptional(context: solid_any)
takesAnyOptional(context: solid_any as Any?)

let solid_anyOpt = solid as Any?
print((solid_anyOpt as? Target)?.name)
takesAnyOptional(context: solid_anyOpt)
takesAnyOptional(context: solid_anyOpt as Any) // -> double optional -> nil

let solid_anyOpt_any = solid_anyOpt as Any
takesAnyOptional(context: solid_anyOpt_any) // -> double optional -> nil

【讨论】:

我遇到了这个问题。添加这个额外的演员为我解决了这个问题。

以上是关于任何不一致的铸造?在可选绑定期间进入 Swift 中的协议的主要内容,如果未能解决你的问题,请参考以下文章

无法在可选绑定中使用可选 int "possibleNumber"

与 try 的可选绑定?并作为?仍然产生一个可选类型

Swift 可选绑定,为啥需要本地 var?

同时初始化和绑定swift可选成员?

为啥必须在可选链接之前使用点运算符 - 在函数之前? [复制]

在 Swift 中将可选绑定转换为错误处理的过程是啥?