2014-11-08 19 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