2014-11-08 38 views
1

我试图从我的网站上的JSON中提取信息。这样做时,如果连接出现错误,它应该返回该错误并将其记录到控制台。我遇到的问题是,如果我打开飞机更多或以其他方式丢失信号,错误:fatal error: unexpectedly found nil while unwrapping an Optional value崩溃应用程序。为什么它返回这个,当我设置了错误的条件来简单地记录?先谢谢你!在NSURLConnection中建立错误案例,在Swift中进行JSON解析

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

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。否则,请忽略该实例。

MealViewController

override func viewDidLoad() { 
    super.viewDidLoad() 

    var req = getJSON("http://www.seandeaton.com/meals/Mealx") 
    loadJSON(req) 


} 

MealModel.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 

    } 

} 

我怎样才能阻止应用失败后轰然建立连接并记录错误消息的安慰?再次感谢。

回答

1

关键的发现是,在调用sendSynchronousRequest你检索NSData中,您已经定义NSData不是可选的,你附加了!这将迫使可选的返回值的解缠。因此,如果可选的NSDatanil(如果有任何网络问题会发生这种情况),则此代码将失败。

取而代之,您应该简单地将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 
+0

非常感谢您的回答 - 我正在使用retrieveJSON实现您答案的后半部分。你提到不使用闭包内的对象,因为它异步运行。什么特别坏?此外,我是否应该简单地返回NSDictionary的内容以便在其他地方执行? 对不起所有的问题。我已经在应用程序中处理了使用JSON文件,但是不得不请求这些数据引入了我尝试熟悉的全新功能。再次感谢你,罗伯。 – Snarf 2014-11-09 02:58:31