数据格式不正确,无法读取?

时间:2020-07-30 15:24:45

标签: json swift

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

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()
    }
}

2 个答案:

答案 0 :(得分:3)

我强烈建议学习如何调试:它包括查找位置,获取哪些信息,从何处获取等等,最后进行修复。

这是一件好事,您可以打印错误,而大多数初学者则不用。

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 :(得分:1)

根据您提供的代码,您似乎在尝试解码Array<Call>,但是在JSON中,数据的格式为Dictionary<String: Call>

您应该尝试:

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