在 NSURLConnection 中建立错误案例,在 Swift 中建立 JSON 解析



我正在尝试从我网站上的JSON中提取信息。这样做时,如果连接有错误,它应该返回该错误并将其记录到控制台。我遇到的问题是,如果我更多地打开飞机或以其他方式失去信号,错误:fatal error: unexpectedly found nil while unwrapping an Optional value会使应用程序崩溃。当我为简单地记录错误设置条件时,为什么它会返回此内容?提前谢谢你!

我不确定为什么没有记录错误并阻止应用程序崩溃。任何指针都会有所帮助。

JSONLoader.swift

import Foundation
var arrayOfMeals: [Meal] = [Meal]()
var weekDayArray = ["monday"]

func getJSON(urlToRequest: String) -> NSDictionary {
    var url: NSURL = NSURL(string: urlToRequest)!
    var jsonRequest: NSURLRequest = NSURLRequest(URL: url)
    var jsonResponse: AutoreleasingUnsafeMutablePointer<NSURLResponse?> = nil
    var error: NSError?
    var dataValue: NSData =  NSURLConnection.sendSynchronousRequest(jsonRequest, returningResponse: jsonResponse, error:&error)!
    if error? == nil {
        var jsonResult: NSDictionary = NSJSONSerialization.JSONObjectWithData(dataValue, options: NSJSONReadingOptions.MutableContainers , error: &error) as NSDictionary
        NSURLRequestCachePolicy.ReloadIgnoringLocalAndRemoteCacheData
        if error? == nil {
            return jsonResult
        }
        else {
            return NSDictionary(object: "Error: Something with parsing went wrong :(", forKey: "error")
        }
    }
    else {
        return NSDictionary(object: "Error: There was an error with your connection :(", forKey: "error")
    }
}
func loadJSON(jsonDictionary: NSDictionary) {
    for days in weekDayArray{
        var resultsArray = jsonDictionary[days] as NSArray
        for obj: AnyObject in resultsArray{
            let breakfast = (obj.objectForKey("breakfast")! as String)
            let lunch = (obj.objectForKey("lunch")! as String)
            let dinner = obj.objectForKey("dinner")! as String
            let dateString = obj.objectForKey("dateString")! as String
            let dayOfWeek = obj.objectForKey("dayOfWeek")! as String
            let newMeal = Meal(breakfast: breakfast, lunch: lunch, dinner: dinner, dayOfWeek: dayOfWeek, dateString: dateString)
            if theDays(newMeal.dateString) >= 0 {
                arrayOfMeals.append(newMeal)
            }
        }
    }

}

我希望函数getJSON能够为站点建立一个NSURLConnection,解析JSON日期,并返回一个NSDictionary。如果连接中存在错误,则会建立错误案例,然后返回字典,其中包含解释错误的值。在解析 JSON 文件时会出现其他错误情况,并返回具有类似错误的 NSDictionary。

我希望函数 loadJSON 能够创建对象Meal的实例,我将其定义为具有早餐、午餐、晚餐、日期和一周中的某一天的属性。此实例的值是从函数 getJSON 返回的 NSDictionary 的结果。如果这一天是未来,请将其附加到我的arrayOfMeals。否则,请忽略该实例。

餐视图控制器

override func viewDidLoad() {
    super.viewDidLoad()
    var req = getJSON("http://www.seandeaton.com/meals/Mealx")
    loadJSON(req)

}

膳食模型.swift - 创建膳食实例

class Meal {
    let breakfast: String
    let lunch: String
    let dinner: String
    let dayOfWeek: String
    let dateString: String
    init(breakfast: String, lunch: String, dinner: String, dayOfWeek: String, dateString: String) {
        self.breakfast = breakfast
        self.lunch = lunch
        self.dinner = dinner
        self.dayOfWeek = dayOfWeek
        self.dateString = dateString
    }
}

如何防止应用程序在建立连接失败时崩溃并将错误消息记录到控制台?再次感谢。

关键的观察结果是,在检索NSDatasendSynchronousRequest调用中,您已将NSData定义为非可选,并附加了一个!,这将强制解包可选的返回值。因此,如果nil可选NSData(如果存在任何网络问题,就会发生这种情况(,则此代码将失败。

相反,您应该简单地将NSData保留为可选(即NSData?(,并在尝试解开包装之前检查它是否nil。因此,我可能会建议如下:

func retrieveJSON(urlToRequest: String) -> NSDictionary {
    let url: NSURL = NSURL(string: urlToRequest)!
    let jsonRequest: NSURLRequest = NSURLRequest(URL: url)
    var jsonResponse: NSURLResponse?
    var error: NSError?
    let dataValue = NSURLConnection.sendSynchronousRequest(jsonRequest, returningResponse: &jsonResponse, error:&error)
    if dataValue != nil {
        if let jsonResult = NSJSONSerialization.JSONObjectWithData(dataValue!, options: .MutableContainers, error: &error) as? NSDictionary {
            return jsonResult
        } else {
            return [
                "error": "Error: Something with parsing went wrong :(",
                "localizedDescription": error?.localizedDescription ?? ""
            ];
        }
    }
    else {
        return [
            "error": "Error: There was an error with your connection :(",
            "localizedDescription": error?.localizedDescription ?? ""
        ];
    }
}

以上将修复由于强制解开可选NSData而导致的崩溃,如果存在网络问题,则会nil。请注意,您没有向我们展示调用getJSON然后随后调用loadJSON的代码,但我假设您正在那里对错误处理进行必要的检查。

请注意,我还停用了笨拙的AutoreleasingUnsafeMutablePointer<NSURLResponse?>结构。我还将错误的localizedDescription添加到返回的字典中。

就个人而言,我通常会返回完整的NSError对象和NSURLResponse对象,以便调用方可以诊断错误的确切性质,而不仅仅是文本描述。


在对代码进行更彻底的编辑时,我建议您通常避免同步请求。切勿从主线程执行同步请求。

例如,您可以定义异步执行请求的方法,如下所示:

func retrieveJSON(urlToRequest: String, completionHandler:(responseObject: NSDictionary?, error: NSError?) -> ()) {
    let url: NSURL = NSURL(string: urlToRequest)!
    let jsonRequest: NSURLRequest = NSURLRequest(URL: url)
    var jsonResponse: NSURLResponse?
    NSURLConnection.sendAsynchronousRequest(jsonRequest, queue: NSOperationQueue.mainQueue()) {
        response, data, error in
        if data == nil {
            completionHandler(responseObject: nil, error: error)
        } else {
            var parseError: NSError?
            let jsonResult = NSJSONSerialization.JSONObjectWithData(data, options: .MutableContainers, error: &parseError) as NSDictionary?
            completionHandler(responseObject: jsonResult, error: error)
        }
    }
}

然后,您可以使用"尾随闭包语法"调用它,如下所示:

retrieveJSON(urlString) {
    responseObject, error in
    if responseObject == nil {
        // handle error here, e.g.
        println(error)
        return
    }
    // handle successful the `NSDictionary` object, `responseObject`, here
}
// but don't try to use the object here, because the above runs asynchronously

最新更新