json - 为什么我的 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"]
解决方案
没有足够的信息来调试此特定问题,但您收到的 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
...
推荐阅读
- node.js - when unit testing shelljs doesn't use my mocked filesystem but the real one
- python - 如果没有返回异常,则传递异常并引发错误的方法
- java - Spring JPA - 具有相同ID的不同实体
- python - pandas dataframe assign random numbers group by
- java - Weblogic 12.2.1.3.0 上的 BeanNotOfRequiredTypeException
- java - MyBatis - Calling stored procedure with custom object
- python - 如何让 python xmlsec 库在 Pivotal Cloud Foundry 上运行
- awk - 两条线之间的距离
- php - 警告:在第 1 行的 * 中使用未定义的常量 php - 假定为“php”(这将在 PHP 的未来版本中引发错误)
- c++ - C++ Poco - 如何向特定线程发送通知/消息?