网络调用因展开而失败

Network call fails due to unwrapping

这是我对 forecast.io 进行网络调用的代码。 在 ViewController 我有:

private let apiKey = ""//my key

override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view, typically from a nib.
    let baseURL = NSURL(string: "https://api.forecast.io/forecast/\(apiKey)")
    let forecastURL = NSURL(string: "37.8267,-122.423", relativeToURL : baseURL)

    let sharedSession = NSURLSession.sharedSession()
    let downloadTask : NSURLSessionDownloadTask = sharedSession.downloadTaskWithURL(forecastURL!, completionHandler: { (location: NSURL!, response: NSURLResponse!, error: NSError!) -> Void in
        if (error == nil) {
            let dataObject = NSData(contentsOfURL: location)
            let weatherDictionary : NSDictionary = NSJSONSerialization.JSONObjectWithData(
                dataObject!, options: nil, error: nil) as! NSDictionary
        }
    })
    downloadTask.resume()
}

我正在尝试将我的数据设置为 NSDictionary 以便能够访问它。我有一个与 weatherDictionary:

有关的错误(绿线)

fatal error: unexpectedly found nil while unwrapping an Optional value

我正在打开 dataObject,所以可能是什么问题?

你真的,真的,需要改掉强制展开的习惯。如果每当你得到一个可选的,你只是使用 ! 来打开它,你将永远遇到这些问题。

这是你的内部代码的一个版本,它在每个回合检查可选值:

let sharedSession = NSURLSession.sharedSession()
let downloadTask = sharedSession.downloadTaskWithURL(forecastURL!)
{ location, response, error in

    if let error = error {
        // log error
    }
    else if let dataObject = NSData(contentsOfURL: location) {

        let weatherObj: AnyObject? = NSJSONSerialization.JSONObjectWithData(
            dataObject, options: nil, error: nil)

        if let weatherDictionary = weatherObj as? NSDictionary {

        }
        else {
            // log error with conversion of weather to dictionary
        }

    }
    else {
        // log error with dataObject
    }
}

是的,这写起来更长也更烦人(不过,类型推断会帮助你走另一条路——你不必显式地键入所有内容,例如在回调中,IMO 更清楚地忽略类型) .

是的,有时你肯定知道一个值不会为零,所以强制解包它更容易和更清晰(例如,使用你的 NSURL - 你可以很安全地使用那个只要不涉及用户输入)。

但在你不bash你的脑袋经常出现空值错误之前,最好以这种方式编写你的代码。

一旦您对处理可选值更加自如, 可以编写更整洁的代码。

您可能还想考虑在处理 JSON 结果时使用更强的类型,例如,您可以执行以下操作:

if let weatherDictionary = weatherObj as? [String:AnyObject]

处理字典内部时依此类推。同样,如果您相信 forecast.io 总是以完全正确的形式为您提供有效的 JSON 数据,您可以跳过这一步并强制执行所有操作,但在编写代码时这将更难调试,并且您有风险如果您取回损坏的数据,您的代码会在生产环境中崩溃(而不是优雅地失败)。