【问题标题】:Downcast from Any to a protocol从 Any 向下转换为协议
【发布时间】:2015-04-08 16:38:50
【问题描述】:

我有以下代码。如何解决最后一行的错误?

protocol Animal {
    func walk()
}

struct Cat: Animal {
    func walk() {}

    init() { }
}

var obj: Any = Cat()
var cat = obj as Animal // ERROR: cannot downcast from Any to unrelated type Animal

【问题讨论】:

  • re:你在最后一行看到的错误,它显示为// ERROR: cannot downcast from Any to unrelated type Animal不是 Cat,对吧?

标签: ios swift


【解决方案1】:

更新:这已在 Swift 1.2+ (Xcode 6.3+) 中得到修复。 Xcode 6.3 beta 发行说明说:

动态转换(“as!”、“as?”和“is”)现在可以与 Swift 协议一起使用 类型,只要它们没有关联的类型。


您只能使用@objc 协议检查协议一致性(包括isasas?)。 Animal 不是 @objc

请参阅 Swift 书籍的 Checking for Protocol Conformance 部分。

注意

只有在您的协议被标记时,您才能检查协议的一致性 带有@objc 属性

【讨论】:

  • 感谢您提供的信息。但奇怪的是,运行时必须能够获取类型信息才能执行Any -> Cat 转换,因此它应该能够找出Cat 符合Animal。我不知道为什么存在这个约束。
  • 这是 Swift 运行时的已知限制,预计为 lifted in a future version
  • 该措辞已从文档中删除(点击链接,您会看到)。现在它只说具有可选要求的协议需要@objc 标记。但是当我尝试检查协议一致性时,我仍然收到编译错误(“无法从 'anyobject' 向下转换为非@objc 协议类型'blah')。有人知道这个要求是否真的被取消了吗?
  • @skypecakes:是的,在 Xcode 6.3 beta (Swift 1.2) 发行说明中,它提到“动态转换(“as!”、“as?”和“is”)现在可以使用 Swift 协议类型,只要它们没有关联的类型。”如果你使用已发布的 Xcode 6.2,它将无法正常工作。
  • @newacct 你能确认一下吗?我正在查看 Xcode 7.0.1 Swift 2.0 中的一个游乐场示例,该示例未能通过条件转换。
【解决方案2】:

您可以通过以下方式解决它

 var cat = obj as Cat as Animal

但是这种解决方法几乎没用...因为您首先需要知道obj 的类型


编辑:

正如@newacct 指出的那样,这不是错误,请参阅他的答案以获取更多信息

xcrun swift
Welcome to Swift!  Type :help for assistance.
  1>
  2> @objc protocol Animal {
  3.         func walk()
  4. }

@objc class Cat: Animal {
    func walk() {}

    init() { }
}

var obj: AnyObject = Cat()

var cat = obj as Animal
  5>
  6> @objc class Cat: Animal {
  7.         func walk() {}
  8.
  9.         init() { }
 10. }
 11>
 12> var obj: AnyObject = Cat()
obj: Cat = {}
 13>
 14> var cat = obj as Animal
cat: Cat = {}
 15>

Animal协议需要@objc属性,Cat需要@objc class

【讨论】:

  • 我不认为这是一个错误,我认为如果您可以将对象转换为协议,它将使类型系统陷入本体危机。 (尽管在 ObjC 中是可能的)
  • 我会鼓励任何遇到此问题的人submit a bug to apple
  • @iluvcapra 任何东西都可以符合协议。而Any 就是protocol<>。我不明白为什么我们不能将Any 转换为Animal。 Type 和 Protocol 在 Swift 中也在同一个命名空间中,这鼓励人们混合使用它们。
  • 对,但强制转换只能影响变量的类型,而协议不是类型。协议验证类型,它们先于类型,但它们本身不能形成完整的类型。类型的必要条件是 ivar 插槽,协议没有 ivar。
  • @iluvcapra @_@ 我迷路了......“类型的必要条件是 ivar 插槽”是什么意思。我不认为他们是相关的
【解决方案3】:

据我观察,AnyObject 只能 向下转换 到类类型的实例 (†) 和 Any 只能向下转换 到类型(类或其他),不可能将它们转换 到协议。 p>

我不知道我是否会将其定性为错误,如果这成立,那么也许它是有充分理由以这种方式实现的 - 但@Bryan 的解决方法(先转换为类型,然后转换为协议)至少“解决了错误”!

(†) 值得注意的例外包括能够从 AnyObject 向下转换为核心数据类型 Int、String 等。

【讨论】:

  • “值得注意的例外包括能够从 AnyObject 向下转换为核心数据类型 Int、String 等。”这是由于基础类型的桥接。如果你不import Foundation 那些演员将不会编译。
【解决方案4】:

我的方法

@objc protocol Animal {
    func walk()
}

@objc class DummyAnimal: Animal {
    func walk() {

    }
}

@objc class Cat: DummyAnimal {
    override func walk() {
        print("meow")
    }

    override init() { }
}

var obj: Any = Cat()
var cat = obj as DummyAnimal
cat.walk()

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-03-14
    • 1970-01-01
    • 1970-01-01
    • 2023-03-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多