【问题标题】:The Data Couldn't Be Read Because It Isn't in The Correct Format?由于格式不正确而无法读取数据?
【发布时间】:2020-11-20 09:21:18
【问题描述】:

根据我的数据,我很确定我的模型是正确的,但我无法弄清楚为什么会出现格式错误?

JSON:

{
   "1596193200":{
      "clientref":1,
      "type":"breakfast"
   },
   "1596200400":{
      "clientref":0,
      "type":"lunch"
   },
   "1596218400":{
      "clientref":2,
      "type":"dinner"
   }
}

型号:

struct Call: Decodable {
    let clientref: Int?
    let type: String?
}

使用从 URL 解码 json 数据的代码编辑更新的问题:

class CallService {
    
    static let shared = CallService()
    let CALLS_URL = "url.com/Calls.json"

    func fetchCalls(completion: @escaping ([Call]) -> ()) {

        guard let url = URL(string: CALLS_URL) else { return }

        URLSession.shared.dataTask(with: url) { (data, response, error) in

            // handle error
            if let error = error {
                print("Failed to fetch data with error: ", error.localizedDescription)
                return
            }

            guard let data = data else {return}

            do {
                let call = try JSONDecoder().decode([Call].self, from: data)
                completion(call)


            } catch let error {
                print("Failed to create JSON with error: ", error.localizedDescription)
            }
        }.resume()
    }
}

【问题讨论】:

  • 试过Codable而不是Decodable
  • 显示您正在解码的代码。我希望你做到了try decoder.decode([String: Call].self... 但这是一个猜测。
  • 错误仍然与codable 相同。我已将我的解码文件添加到问题中。
  • print("Failed to create JSON with error: ", error.localizedDescription) => `print("Failed to create JSON with error: ", error),这样好多了,并给出错误。我们可以很容易地猜出哪里出了问题,但重要的是你要学会在哪里寻找错误,并把它做好。此外,如果它失败了,请不要犹豫:print("It failed with data stringified: \(String(data: data, encoding: .utf8)")),就在错误之后。
  • @Larme 谢谢!非常有帮助。我现在收到了错误"Expected to decode Array<Any> but found a dictionary instead.", underlyingError: nil))

标签: json swift


【解决方案1】:

我强烈建议学习如何调试:它包括在哪里查看、获取什么信息、从哪里获取它们等等,最后,修复它。

打印错误是件好事,大多数初学者不会。

print("Failed to create JSON with error: ", error.localizedDescription)

=>

print("Failed to create JSON with error: ", error)

你会得到一个更好的主意。

其次,如果失败,则打印字符串化的数据。你应该有 JSON,这是正确的。但是我多久看到一次关于这个问题的问题,事实上,答案根本不是 JSON(API 从未声明它将返回 JSON),作者面临错误(自定义 404 等)并且确实得到了XML/HTML 消息错误等。

所以,当解析失败时,我建议这样做:

print("Failed with data: \(String(data: data, encoding: .utf8))")

检查输出是否是有效的 JSON(大量在线验证器或执行此操作的应用程序)。

现在:

根据我的数据,我很确定我的模型是正确的,

嗯,是的,也不是。

Codable 首次亮相时的小技巧(而不是使用嵌套的东西):做相反的事情。

如果还不是这样,请让你的结构可编码(我使用 Playgrounds)

struct Call: Codable {
    let clientref: Int?
    let type: String?
}


do {
    let calls: [Call] = [Call(clientref: 1, type: "breakfast"),
                          Call(clientref: 0, type: "lunch"),
                          Call(clientref: 2, type: "dinner")]
    
    let encoder = JSONEncoder()
    encoder.outputFormatting = [.prettyPrinted]
    let jsonData = try encoder.encode(calls)
    let jsonStringified = String(data: jsonData, encoding: .utf8)
    if let string = jsonStringified {
        print(string)
    }
} catch {
    print("Got error: \(error)")
}

输出:

[
  {
    "clientref" : 1,
    "type" : "breakfast"
  },
  {
    "clientref" : 0,
    "type" : "lunch"
  },
  {
    "clientref" : 2,
    "type" : "dinner"
  }
]

看起来不像。我只能使用一个数组将各种调用放在一个变量中,这就是你要解码的意思,因为你写了[Call].self,所以你期待一个Call的数组。我们缺少“1596218400”部分。等等,它会是顶级字典吗?是的。您可以看到{} 以及它使用“键”这一事实,而不是一个接一个地列出...

等等,现在我们打印了完整的错误,现在更有意义了吗?

typeMismatch(Swift.Array<Any>, 
             Swift.DecodingError.Context(codingPath: [],         
                                         debugDescription: "Expected to decode Array<Any> but found a dictionary instead.", 
                                         underlyingError: nil))

修复:

let dictionary = try JSONDecoder().decode([String: Call].self, from: data)
completion(dictionary.values) //since I guess you only want the Call objects, not the keys with the numbers.

【讨论】:

  • +1 很好的解释。我们多久会看到以无法读取数据因为格式不正确...开头的问题
  • 太多次了,这让我在不太懒惰的时候开始写一篇关于调试技巧的文章。
  • 非常有帮助的解释。问题解决了,我获得了有关调试的知识。非常感谢!
  • 如果我想从每个字典成员那里获取密钥,用这段代码可以吗?我可以calls?.key 吗?
  • 你有一本字典,所以你可以使用dictionary.valuesdictionary.keys。这取决于你想要什么。您也可以直接返回dictionary
【解决方案2】:

从您提供的代码看来,您正在尝试解码 Array&lt;Call&gt;,但在 JSON 中,数据被格式化为 Dictionary&lt;String: Call&gt;

你应该试试:

let call = try JsonDecoder().decode(Dictionary<String: Call>.self, from: data)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-06-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-07-08
    • 2016-10-15
    • 1970-01-01
    相关资源
    最近更新 更多