首页 > 解决方案 > 为什么我的 JSON 请求失败率超过 50%?

问题描述

我正在制作一个从牛津词典的 API 中获取单词的拼字游戏。该应用程序提供了预期的单词,但它的失败率比我想要的要高。我的成功率大约是 25% 到 36%;大多数单词都会产生 nil 结果,但这显然是我的错,而不是 API 的错。我想要更高的成功率,因为​​ API 不是免费的。或者这种命中率对于主要 API 来说是典型的吗?

我知道我需要将其更改为 Swift 4 的 Decodable for JSON,但我还没有弄清楚那个。

你能在我的代码中找到任何会导致完全简单的单词被跳过的东西,例如任何字典中的单音节单词吗?在代码的末尾,我添加了成功和失败单词的示例控制台日志。

func speakRandomWord() {
 //Now that a valid random word is selected, this where I make my API call.


   appId = "private"
   appKey = "private"
   language = "en"
   word = randomWord //I get the random word from Lexicontext, Oxford API doesn't support random words yet. I filter out entriest that aren't one word.
   regions = "gb"
   word_id = word.lowercased() 
   url = URL(string:"https://odapi.oxforddictionaries.com:443/api/v1/entries/\(language)/\(word_id)/regions=\(regions)")!
    var request = URLRequest(url: url)
    request.addValue("application/json", forHTTPHeaderField: "Accept")
    request.addValue(appId, forHTTPHeaderField: "app_id")
    request.addValue(appKey, forHTTPHeaderField: "app_key")

    let session = URLSession.shared
    print ("URLSession began...")
    dataAttempted += 1
    _ = session.dataTask(with: request, completionHandler: { data, response, error in
    if let httpResponse = response as? HTTPURLResponse {
    print("statusCode: \(httpResponse.statusCode)")

    if httpResponse.statusCode != 200 {

        print ("URLSession failed, trying again...")
        self.urlSessionFailed += 1
        self.selectRandomWord()
        self.speakRandomWord()
        }

   }

   DispatchQueue.main.async { [unowned self] in
   self.activitySpinner.stopAnimating()
   self.activitySpinner.isHidden = true
   self.theUserInput.becomeFirstResponder()
   self.repeatButton.isEnabled = true
   self.defineButton.isEnabled = true


}

    if let response = response,
        let data = data,
        let jsonData = try? JSONSerialization.jsonObject(with: data, options: .mutableContainers) as? [String:AnyObject]

        {

if
let dictionary = jsonData as? [String: Any],

let results = dictionary["results"] as? [[String: Any]],
!results.isEmpty, case var result = results[0],

let lexicalEntries = result["lexicalEntries"] as? [[String: Any]],
!lexicalEntries.isEmpty, case var lexicalEntry = lexicalEntries[0],

let derivatives = lexicalEntry["derivatives"] as? [[String:Any]],
!derivatives.isEmpty, case var derivative = derivatives[0],

let pronunciations = lexicalEntry["pronunciations"] as? [[String: Any]],
!pronunciations.isEmpty, case var pronunciation = pronunciations[0],

let entries = lexicalEntry["entries"] as? [[String:Any]],
!entries.isEmpty, case var entry = entries[0],

    let senses = entry["senses"] as? [[String:Any]],
    !senses.isEmpty, case var sense = senses[0],

    let examples = sense["examples"] as? [[String:Any]],
    !examples.isEmpty, case var example = examples[0] 

//Now I pick out details from the JSON like audio, sample sentence, etc.

 {

if let theText = example.removeValue(forKey:"text") {

self.theText = String(describing:theText)
 print ("The value is \(self.theText)")

}


if let meaning = sense.removeValue(forKey:"short_definitions") {

self.newMeaning = String(describing:meaning)
print ("The short meaning is \(self.meaning)")

}


if let origin = entry.removeValue(forKey:"etymologies") {



    self.newEtymology = String(describing:origin)

    self.decoded2 = String(self.newEtymology.characters.filter({!"U0123456789".contains(String($0))}))

   // print ("The etymology is \(self.decoded2)")

            }

if let audioPath = pronunciation.removeValue(forKey:"audioFile") {
    print ("MP3 audio file for \(self.word) exists")
    print (audioPath)
    self.audioPaths.append(audioPath as! String)
    self.dataIsValid += 1
    self.successfulWords.append(self.word)


   self.path = String(describing:audioPath)
    self.repeatPath = self.path
    print (self.path)
   if let url = URL.init(string: self.path) {
    self.player = AVPlayer.init(url: url)
   self.player.play()
    }


}

else {
    print ("No audio data for \(self.word)!")
    self.dataFailed += 1
    self.audioFailed.append(self.word)
    self.selectRandomWord()


   }

}
    else {
    print ("\(self.randomWord) failed, reason unknown!")
    self.dataFailed += 1
    self.failedOtherReason.append(self.word)
    self.selectRandomWord()

       }
    }


}).resume()

}

 // Console results:
 //URL Session failures: 5
 //API attempts: 41.0
 //API successes: 15.0
 //API failures: 21.0
 //Successful Oxford API hit percentage: 36.5853658536585

 //These 15 words succeeded: ["denunciation", "strategic", "strategic",  "detract", "opaline", "opaline", "jurist", "exit", "throaty", "mother", "mother", "regroup", "early", "managerial", "recalcitrant"]

  //These 0 words had no audio: []

  //These words 21 words failed for an unknown reason: ["overlook", "lignin", "mandate", "evident", "anagrammatize", "avoirdupois", "extraterrestrial", "opaline", "cauterization", "malted", "clear", "snuggle", "fresno", "jurist", "streamline", "nonconforming", "trochee", "adventitia", "rudiment", "sculpturesque", "bicycle"]

标签: jsonswift

解决方案


没有足够的信息来调试此特定问题,但您收到的 JSON 响应可能包含可选字段。对于某些响应,预期为空的字段。这部分代码,

  if
    let dictionary = jsonData as? [String: Any],
    let results = dictionary["results"] as? [[String: Any]],
    !results.isEmpty,
    case var result = results[0],
    let lexicalEntries = result["lexicalEntries"] as? [[String: Any]],
    !lexicalEntries.isEmpty,
    case var lexicalEntry = lexicalEntries[0],
    let derivatives = lexicalEntry["derivatives"] as? [[String:Any]],
    !derivatives.isEmpty,
    case var derivative = derivatives[0],
    let pronunciations = lexicalEntry["pronunciations"] as? [[String: Any]],
    !pronunciations.isEmpty, case var pronunciation = pronunciations[0],
    let entries = lexicalEntry["entries"] as? [[String:Any]],
    !entries.isEmpty,
    case var entry = entries[0],
    let senses = entry["senses"] as? [[String:Any]],
    !senses.isEmpty, case var sense = senses[0],
    let examples = sense["examples"] as? [[String:Any]],
    !examples.isEmpty,
    case var example = examples[0]
    //Now I pick out details from the JSON like audio, sample sentence, etc.
  {

需要拆分以处理(和报告)丢失的字段。那就是在你的“好”路径执行之前必须通过的 20 个布尔测试。可能发生的是您的字典访问失败。例如,如果字典不包含“lexicalEntries”,那么它将采用失败路径并且不会像您期望的那样返回空数组。

确认相同的单词每次都失败。查看实际 JSON 中是否有失败的单词,并确保每个字段都被报告。

更新:

if let response = response,
  let data = data,
  let jsonData = try? JSONSerialization.jsonObject(with: data, options: .mutableContainers) as? [String:AnyObject]
{
  guard let dictionary = jsonData as? [String: Any] else {
    print("Error: dictionary was not returned by endpoint")
    return
  }
  guard let results = dictionary["results"] as? [[String: Any]] else {
    print("Error: no results array returned by endpoint")
    return
  }
  result = results.first
  ...

推荐阅读