Swift AnyObject 转换

Swift AnyObject Conversion

我创建了一些 test code 来说明我遇到的问题。

这在操场上编译得很好,但是,当我尝试将其放入项目时,Xcode 给出以下警告:Treating a forced downcast to 'String' as optional will never produce 'nil' on line 30。我得到了两个解决问题的建议:

  1. Use 'as?' to perform a conditional downcast to 'String',这完全没有意义。但是,它确实在没有 warnings/errors 的情况下进行编译,这看起来很奇怪,因为它将一个可选值分配给 String.

    的非可选类型

    Use the conditional form of the type cast operator (as?) when you are not sure if the downcast will succeed. This form of the operator will always return an optional value, and the value will be nil if the downcast was not possible. This enables you to check for a successful downcast.

    来自Swift language guide.

    除非它认为如果转换失败我可能想分配 nil (因此删除字典条目),这是没有意义的。特别是因为我确信它会成功,因为我确实只是检查它是否是 String.

  2. Add parentheses around the cast to silence this warning,这似乎毫无意义,但 确实 消除了警告。这似乎是一件奇怪的事情,但话又说回来,这可能只是确认你真的想做你想做的事情的一种糟糕方式。


哪个选项是正确的,还是都不正确?是什么导致此警告?

正确的解决方案是使用可选绑定而不是 强制展开运算符 !。实际上你可以合并支票 value != nil 进入 switch 语句:

for (key, value) in dict {
    switch value {
    case let s as String:
        newDict[key] = s
    case let i as Int:
        newDict[key] = String(i)
    case let b as Bool:
        newDict[key] = b ? "1" : "0"
    case let v?:   // value is not `nil`
        newDict[key] = String(v)
    default:       // value is `nil`
        break
    }
}

这是您的代码,经过修改以显示如何转换函数结果以匹配 AnyObject? 并避免显式展开可选值:

func returnsAString() -> AnyObject? {
  return "I am a String." as? AnyObject
}

func returnsAnInt() -> AnyObject? {
  return Int(123) as? AnyObject
}

func returnsABool() -> AnyObject? {
  return true as? AnyObject
}

func returnsNilBool() -> AnyObject? {
  return nil as Bool? as? AnyObject
}

var dict    : [String : AnyObject?] = [String : AnyObject?]()
var newDict : [String : String    ] = [String : String    ]()

dict["string"] = returnsAString()
dict["int"] = returnsAnInt()
dict["bool"] = returnsABool()
dict["nil"] = returnsNilBool()

for (key, value) in dict {
    switch value {
    case let value as String:
      newDict[key] = value
    case let value as Int:
      newDict[key] = String(value)
    case let value as Bool:
      newDict[key] = (value ? "1" : "0")
    default:
      newDict[key] = "nil"
    }
}

print("Dict: \(dict)")
print("newDict: \(newDict)")

// Dict: ["nil": nil, "int": Optional(123), "bool": Optional(1), "string": Optional(I am a String.)]
// newDict: ["nil": "nil", "int": "123", "bool": "1", "string": "I am a String."]