无法将 NSDictionary 类型的值分配给 NSDictionary 类型的值

Cannot assign value of type NSDictionary to a value of type NSDictionary

Swift 2.0 (Xcode 7 Beta 3),据我所知语法看起来很棒。我之前获得了一个 JSON 字符串,然后当我尝试解析它时,我在 "try NSJSONSerialization" 行的 "as" 关键字上得到了上述错误。我做错了什么?感谢您的回答。

        var weatherData: NSDictionary
        do {
            weatherData = try NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.MutableContainers) as! NSDictionary
        } catch {
            // Display an error to user
            let errorAlert = UIAlertController(title: "Error", message: "Unable to get weather data", preferredStyle: UIAlertControllerStyle.Alert)
            self.presentViewController(errorAlert, animated: true, completion: nil)
            return
        }

您可以使用 ! 强制转换为 NSDictionary(但最好像@robertvojta 的回答那样使用 "guard")。

此外,您可以使用 [] 代替 MutableContainers:

weatherData = try NSJSONSerialization.JSONObjectWithData(data!, options: []) as! NSDictionary

编辑:根据@robertvojta 的回答和解释,我已经删除了我关于 Swift 2 和在 "do ... catch" 内强制转换的错误断言。另外,请注意,在屏幕截图中,NSData 当然只是用于在 Playground 中进行快速测试。

@EricD 在他的回答中写的是错误的。引用:

With Swift 1.2 using ! was dangerous and it was better to use Optional binding (if let ...) but in Swift 2 when you handle the errors with do catch, you can actually use ! (but one should not forget to use a generic catch, like you do, in addition to possible other specific error handling).

do catch 只处理并且只处理(重新)抛出的错误。没有其他的。如果您强制解包可选 nil,您将收到 EXC_BAD_INSTRUCTIONfatal error: unexpectedly found nil while unwrapping an Optional value。即使您的代码包含在 do catch 中,您也会得到它。像 throwscatch 这样的关键字可以让人联想到它是关于异常的,但它不是——只是错误。同样适用于 as!.

改写成这样:

enum MyError: ErrorType {
  case ParsingFailed
}

// some jsonData you did receive
var jsonData: NSData?

do {
  guard let data = jsonData,
    weatherData = try NSJSONSerialization.JSONObjectWithData(data, options: .MutableContainers) as? NSDictionary else {
      throw MyError.ParsingFailed
  }

  // here you can work with your weatherData dictionary in a safe way
  // it's NSDictionary and not an optional
}
catch {
  // Display an error to user
}

它的作用:

  • jsonData 包含(或不包含)NSData 您确实收到了回复,
  • guard let data = jsonData 尝试从 optional 获取值,如果成功,展开的值存储在 data 中,否则 MyError.ParsingFailed 被抛出,
  • weatherData = ... 仅在前一个 guard 语句成功时执行,
    • 它尝试从数据创建 JSON 对象,如果失败,将抛出错误,
    • 如果成功,它会尝试将其转换为 NSDictionary (as?),如果也成功,weatherData 包含您的 NSDictionary 否则 MyError.ParsingFailed 被抛出

这是安全的,不会崩溃,所有错误都在一处处理。

所以,不要使用@EricD 写的东西。使用 as!! 仍然是危险的 即使在 Swift 2.

NSData(contentsOfURL:options:) 也不是好主意。这是同步调用,因此,它将阻塞您的主线程(应用程序看起来像冻结了),直到请求失败或成功。