2016-03-08 28 views
0

我想從一個URL獲取JSON文件並使用Swift返回內容。但是,代碼在以下代碼中的行let httpResponse = response as! NSHTTPURLResponse處失敗。我在這條線上得到一個異常,Xcode進入調試模式。下載JSON數據在NSHTTPURLResponse失敗

class func downloadJSONFile()->AnyObject 
    { 
     let requestURL: NSURL = NSURL(string: "http://www.learnswiftonline.com/Samples/subway.json")! 
     let urlRequest: NSMutableURLRequest = NSMutableURLRequest(URL: requestURL) 
     let session = NSURLSession.sharedSession() 
     var json:AnyObject = "" 
     let task = session.dataTaskWithRequest(urlRequest) { 
      (data, response, error) -> Void in 

      let httpResponse = response as! NSHTTPURLResponse 
      let statusCode = httpResponse.statusCode 

      if (statusCode == 200) { 

       do{ 
        json = try NSJSONSerialization.JSONObjectWithData(data!, options:.AllowFragments) 

       }catch { 
        print("Error with Json: \(error)") 

       } 

      } 

     } 

     task.resume() 

     return json 
    } 

我該如何解決這個問題?

+1

你不*從異步調用的返回*。示例:http://stackoverflow.com/a/35358750/2227743另外,您不應強制轉換響應,它可能不在此處,因此請首先檢查錯誤參數。 – Moritz

回答

3

有幾個問題:

  1. 如果在請求中的任何錯誤,responsenil,因而你的企圖迫使投它會導致致命的錯誤。處理網絡響應時不要使用強制解包/轉換。

  2. 這裏有一個更深層的問題,你試圖從異步運行的方法返回數據。你應該改變你的方法不返回任何東西本身,而是提供一個完成處理程序,通過它可以異步地傳回相關數據:

    class func downloadJSONFile(completionHandler:(AnyObject?) ->()) { 
        let requestURL: NSURL = NSURL(string: "http://www.learnswiftonline.com/Samples/subway.json")! 
        let urlRequest: NSMutableURLRequest = NSMutableURLRequest(URL: requestURL) 
        let session = NSURLSession.sharedSession() 
        let task = session.dataTaskWithRequest(urlRequest) { data, response, error in 
    
         // check for fundamental networking errors 
    
         guard error == nil && data != nil else { 
          print(error) 
          completionHandler(nil) 
          return 
         } 
    
         // check to see if status code found, and if so, that it's 200 
    
         guard let httpResponse = response as? NSHTTPURLResponse where httpResponse.statusCode == 200 else { 
          completionHandler(nil) 
          return 
         } 
    
         do { 
          let json = try NSJSONSerialization.JSONObjectWithData(data!, options:[]) 
          completionHandler(json) 
         } catch let parseError as NSError { 
          print("Error with Json: \(parseError)") 
          completionHandler(nil) 
         } 
        } 
    
        task.resume() 
    } 
    

    ,然後你怎麼稱呼它,使用完成處理程序(或使用尾隨的閉包語法,像圖所示):

    APIClass.downloadJSONFile() { json in 
        guard json != nil else { 
         print("there was some problem") 
         return 
        } 
    
        // now you can use `json` here 
    
        dispatch_async(dispatch_get_main_queue()) { 
         // and if you're doing any model or UI updates, dispatch that back to the main queue 
        } 
    } 
    
    // but do not use `json` here, as the above runs asynchronously 
    

    注意,如果你想提供錯誤信息返回給調用程序,你可以改變它也返回錯誤信息,例如:

    enum DownloadError : ErrorType { 
        case NetworkError(NSError?) 
        case NotHTTPResponse 
        case InvalidHTTPResponse(Int) 
        case JSONError(NSError) 
    } 
    
    class func downloadJSONFile(completionHandler:(AnyObject?, ErrorType?) ->()) { 
        let requestURL: NSURL = NSURL(string: "http://www.learnswiftonline.com/Samples/subway.json")! 
        let urlRequest: NSMutableURLRequest = NSMutableURLRequest(URL: requestURL) 
        let session = NSURLSession.sharedSession() 
        let task = session.dataTaskWithRequest(urlRequest) { data, response, error in 
    
         guard error == nil && data != nil else { 
          completionHandler(nil, DownloadError.NetworkError(error)) 
          return 
         } 
    
         guard let httpResponse = response as? NSHTTPURLResponse else { 
          completionHandler(nil, DownloadError.NotHTTPResponse) 
          return 
         } 
    
         guard httpResponse.statusCode == 200 else { 
          completionHandler(nil, DownloadError.InvalidHTTPResponse(httpResponse.statusCode)) 
          return 
         } 
    
         do { 
          let json = try NSJSONSerialization.JSONObjectWithData(data!, options:[]) 
          completionHandler(json, nil) 
         } catch let parseError as NSError { 
          completionHandler(nil, DownloadError.JSONError(parseError)) 
         } 
        } 
    
        task.resume() 
    } 
    

    而且,很明顯,通話將改變拿兩個參數:

    APIClass.downloadJSONFile() { json, error in 
        guard json != nil && error == nil else { 
         print("there was some problem \(error)") 
         return 
        } 
    
        // and then it would be like before ... 
    } 
    
  3. 當在iOS中使用9和NSURLSession以後,它不會允許明文請求(即「http」是不允許的,默認情況下只有「https」)。您可以強制應用通過將以下內容添加到您的info.plist來允許非https請求。見https://stackoverflow.com/a/31254874/1271826更多信息

    <key>NSAppTransportSecurity</key> 
    <dict> 
        <key>NSExceptionDomains</key> 
        <dict> 
         <key>learnswiftonline.com</key> 
         <dict> 
          <!--Include to allow subdomains--> 
          <key>NSIncludesSubdomains</key> 
          <true/> 
          <!--Include to allow HTTP requests--> 
          <key>NSTemporaryExceptionAllowsInsecureHTTPLoads</key> 
          <true/> 
          <!--Include to specify minimum TLS version--> 
          <key>NSTemporaryExceptionMinimumTLSVersion</key> 
          <string>TLSv1.1</string> 
         </dict> 
        </dict> 
    </dict>