2016-03-08 30 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>