簡體   English   中英

解析 Swift 中的 JSON 時如何處理結構中的錯誤

[英]How do I handle errors within a struct when parsing JSON in Swift

我正在調用 API 然后使用下面的簡化代碼對其進行解碼


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

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

    let decoder = JSONDecoder()
    if let data = data {
        do {
            let results = try decoder.decode(Response.self, from: data)
            print(results)
        } catch {
            print(error)
        }
    }
}
task.resume()

Response 是我的結構,如下所示

struct Response : Codable {
    let response: ResponseContents
}

struct ResponseContents : Codable {
    let result : [wantedData]
}

struct wantedData : Codable {
    let name: String
}

然而,在大多數情況下,這很好用,有時 API 返回一個 JSON,它沒有名為name的鍵,而是鍵是otherName - 因此我收到一個錯誤,說“keyNotFound”。

有沒有辦法可以在我的結構或解析語句中添加一個條件語句來檢查是否找不到密鑰,如果沒有,它使用我定義的另一個?

Larme 給出的解決方案也很好。

但是您也可以直接將 Decodable 與 CodingKey 一起使用,更難閱讀,但可重用。

struct DynamicKey: CodingKey {
    var stringValue: String
    init?(stringValue: String) {
        self.stringValue = stringValue
    }
}


struct wantedData : Codable {
    let name: String

 init(from decoder: Decoder) throws {
      let dynamicKeysContainer = try decoder.container(keyedBy: DynamicKey.self)
      try dynamicKeysContainer.allKeys.forEach { key in
          switch key.stringValue {
          case "name" where try dynamicKeysContainer.decode(String.self, forKey: key):
              name = $0
          case "otherName" where try dynamicKeysContainer.decode(String.self, forKey: key):
              name = $0
          default: break
          }
      }
  }
} 

我沒試過。 而且您可能會做得更好,只需發布​​以提供幫助。

您只需要一個額外的解碼密鑰和一個手動解碼器:

對於這樣的數據,其中“name”和“otherName”是可能的參數:

let json = Data("""
[
    {
        "name": "Alice",
        "age": 43
    },
    {
        "otherName": "Bob",
        "age": 25
    }
]
""".utf8)

像這樣的結構:

struct Person {
    var name: String
    var age: Int
}

然后解碼看起來像這樣:

extension Person: Decodable {
    enum CodingKeys: CodingKey {
        case name
        case otherName  // Keys do not have to be the same as properties
        case age
    }

    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)

        // Try both approaches:
        self.name = try container.decodeIfPresent(String.self, forKey: .name) ??
                        container.decode(String.self, forKey: .otherName)

        // Other, default handling
        self.age = try container.decode(Int.self, forKey: .age)
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM