在NSHTTPURLResponse下载JSON数据失败

时间:2016-03-08 19:57:52

标签: swift nsurlsession nsjsonserialization

我正在尝试从URL获取JSON文件并使用Swift返回内容。但是,代码在以下代码中的let httpResponse = response as! NSHTTPURLResponse行失败。我在这一行得到一个异常,Xcode进入调试模式。

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 个答案:

答案 0 :(得分:4)

有一些问题:

  1. 如果请求中有任何错误,response将为nil,因此您强制转换它的尝试将导致致命错误。处理网络响应时,请勿使用强制解包/强制转换。

  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>