Swift AnyObject转换

3

我创建了一些测试代码来展示我遇到的问题。

在playground中编译没有问题,但是当我尝试将它放入项目中时,Xcode会给出以下警告:将强制向下转型为“String”视为可选项永远不会产生“nil”,位于第30行。我有两个修复问题的建议:

  1. 使用'as?'进行条件向下转换为'String',这似乎毫无意义。然而,它可以编译通过而没有警告/错误,这似乎很奇怪,因为它将可选值赋给了非可选类型的'String'。

    当您不确定向下转换是否成功时,请使用类型转换运算符(as?)的条件形式。该运算符的这种形式将始终返回可选值,如果向下转换不可能,则该值将为nil。这使您能够检查向下转换是否成功。

    来自Swift语言指南

    除非它认为我可能想要在转换失败时分配'nil'(从而删除字典条目),否则这没有任何意义。特别是因为我确信它会成功,因为我刚刚检查过它是否为'String'。

  2. 在强制转换周围添加括号以消除此警告,这似乎毫无意义,但确实消除了警告。这似乎是一种奇怪的做法,但另一方面,这可能只是确认您确实想要执行正在尝试执行的操作的一种不良方式。


哪个选项是正确的,或者两个都不是?是什么导致了这个警告?


这段代码存在很多问题。首先,你需要在函数中显式地进行类型转换,以便返回一个 AnyObject? 类型。其次,你应该尽可能避免使用 ! 进行可选类型的显式解包。 - user887210
@originaluser2 很好的建议,我已经更新了我的代码。 - Coder-256
@ColGraff,问题在于函数可能会返回不同类型的值(这只是例子)。此外,如果我已经测试了它们是否为nil,为什么要避免显式取消可选项? - Coder-256
有更好、更少出错的测试和解包方式,例如 if let unwrapped = wrapped {} - user887210
@ColGraff 那不是真的 - Coder-256
是的,它们生成相同的字节码,但要避免使用它的真正原因是为了避免后期出现问题。首先,使用可选绑定可以将测试和解包放在同一行中。以后的修改不太可能以引发错误的方式改变这种结构。其次,显式解包是一个运行时错误,对代码进行编辑可能导致检查不再覆盖解包,从而在应用程序被使用时而不是在开发时崩溃。可选绑定避免了运行时崩溃,因为测试和解包是单个操作。 - user887210
2个回答

6
正确的解决方案是使用可选绑定而不是强制解包运算符!。实际上,您可以将检查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
    }
}

我知道那个方法,但它似乎与我的方式相同。然而,它确实解决了问题! - Coder-256
@Coder256:警告似乎确实是由于LHS的类型是可选的。但请注意,编译器可能无法“看到”您已经检查了变量的类型。可选绑定可以避免这些问题。 - Martin R

0

这是您的代码,修改后以显示如何将函数结果转换为匹配 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."]

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接