2016-03-08 2 views
0

Я пытаюсь получить JSON-файл из URL-адреса и возвращать содержимое с помощью 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. Если есть какая-либо ошибка в запросе, 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. NSURLSession При использовании в прошивкой 9 и позже, это не позволит незашифрованные запросы (т.е. «http» не разрешено, только по умолчанию «https»). Вы можете заставить приложение разрешать запросы без https, добавив следующее к вашему info.plist. См 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> 
    
Смежные вопросы