根据其他答案的建议,您可以在 JSONSerialization 或 JSONDecoder 解码 API 结果后解码 Data 或 Base-64 String。
但是如果你更喜欢写解码初始化器,你可以这样写:
我猜这可能和你自己的Response 没有太大区别。
struct Response: Codable {
var responseCode: Int
var results: [Result]
enum CodingKeys: String, CodingKey {
case responseCode = "response_code"
case results
}
}
为了准备为Response 编写解码初始化器,我想使用一些扩展:
extension KeyedDecodingContainer {
func decodeBase64(forKey key: Key, encoding: String.Encoding) throws -> String {
guard let string = try self.decode(String.self, forKey: key).decodeBase64(encoding: encoding) else {
throw DecodingError.dataCorruptedError(forKey: key, in: self,
debugDescription: "Not a valid Base-64 representing UTF-8")
}
return string
}
func decodeBase64(forKey key: Key, encoding: String.Encoding) throws -> [String] {
var arrContainer = try self.nestedUnkeyedContainer(forKey: key)
var strings: [String] = []
while !arrContainer.isAtEnd {
guard let string = try arrContainer.decode(String.self).decodeBase64(encoding: encoding) else {
throw DecodingError.dataCorruptedError(forKey: key, in: self,
debugDescription: "Not a valid Base-64 representing UTF-8")
}
strings.append(string)
}
return strings
}
}
使用上面的这些扩展,你可以定义Result类型如下:
extension Response {
struct Result: Codable {
var category: String
var type: String
var difficulty: String
var question: String
var correctAnswer: String
var incorrectAnswers: [String]
enum CodingKeys: String, CodingKey {
case category
case type
case difficulty
case question
case correctAnswer = "correct_answer"
case incorrectAnswers = "incorrect_answers"
}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
self.category = try container.decodeBase64(forKey: .category, encoding: .utf8)
self.type = try container.decodeBase64(forKey: .type, encoding: .utf8)
self.difficulty = try container.decodeBase64(forKey: .difficulty, encoding: .utf8)
self.question = try container.decodeBase64(forKey: .question, encoding: .utf8)
self.correctAnswer = try container.decodeBase64(forKey: .correctAnswer, encoding: .utf8)
self.incorrectAnswers = try container.decodeBase64(forKey: .incorrectAnswers, encoding: .utf8)
}
}
}
(您没有提到您的Response(或其他名称?)是否定义为嵌套类型,但我认为您可以自己重命名或修改它。)
通过以上所有内容,您可以简单地将 API 响应解码为:
do {
let decoder = JSONDecoder()
let questionData = try decoder.decode(Response.self, from: data)
print(questionData)
} catch {
print("Error", error)
}
顺便说一句,我认为最好的解决方案是使用 base64 编码(因为 Swift 似乎支持它),但这是真的吗?
JSONDecoder 支持 Base-64 到 Data,但这不是您所期望的。因此,使用另一种编码可能是更好的选择。
但是,无论如何,JSON 字符串可以仅使用带有 \uXXXX 或 \uHHHH\uLLLL 的 ASCII 表示所有 unicode 字符。所以,我不明白为什么 API 设计者不提供选项标准 JSON 编码。如果您可以联系他们,请告诉他们提供选项,这可能会简化许多客户端代码。