这是我对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
:
致命错误:在解包可选值时意外发现nil
我正在展开dataObject
,那么可能是什么问题?
答案 0 :(得分:3)
你真的,真的,需要摆脱强行解缠的习惯。如果你得到一个可选项,你只需用!
打开它,就会永远遇到这些问题。
以下是内部代码的一个版本,用于检查每个回合的选项:
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将关闭类型)。 / p>
是的,有时你肯定知道一个值不会是零,所以只需要强行打开它就会更容易和更清洁(例如用你的NSURL
- 你可以非常安全地使用那个因为没有涉及用户输入。)
但是直到你不断地对抗零值错误,你最好以这种方式编写你的代码。
在处理选项后,explore the other techniques编写更整洁的代码会更加舒适。
您可能还想在处理JSON结果时考虑使用更强的类型,例如,您可以执行以下操作:
if let weatherDictionary = weatherObj as? [String:AnyObject]
等处理字典内部时。同样,如果您信任forecast.io
始终以完全正确的形式提供有效的JSON数据,您可以跳过此步骤并强制执行所有操作,但在编写代码时将更难调试,并且您冒着代码冒险的风险在生产中(而不是优雅地失败)如果你得到了腐败的数据。