ios - 在 iOS 上使用 Swift 从 Gmail API 响应创建对象时出现“keyNotFound”错误
问题描述
我正在使用 Alamofire 通过邮件 ID 从 Gmail API 获取电子邮件:
AF.request("https://www.googleapis.com/gmail/v1/users/me/messages/\(id)?format=full", headers: headers)
.responseJSON { [self] response in
do {
let json = try JSON(data: response.data!)
if let rawString = json.rawString() {
let email = try Email(rawString)
} else {
print("json.rawString is nil")
}
emailFetchGroup.leave()
}
catch {
print(error)
emailFetchGroup.leave()
}
}
我有以下类,Email
我试图通过 JSON 响应创建:
// This file was generated from JSON Schema using quicktype, do not modify it directly.
// To parse the JSON, add this file to your project and do:
//
// let email = try Email(json)
import Foundation
// MARK: - Email
class Email: Codable {
let sizeEstimate: Int
let historyID, threadID: String
let payload: Payload
let internalDate, snippet, id: String
let labelIDS: [String]
enum CodingKeys: String, CodingKey {
case sizeEstimate
case historyID = "historyId"
case threadID = "threadId"
case payload, internalDate, snippet, id
case labelIDS = "labelIds"
}
init(sizeEstimate: Int, historyID: String, threadID: String, payload: Payload, internalDate: String, snippet: String, id: String, labelIDS: [String]) {
self.sizeEstimate = sizeEstimate
self.historyID = historyID
self.threadID = threadID
self.payload = payload
self.internalDate = internalDate
self.snippet = snippet
self.id = id
self.labelIDS = labelIDS
}
}
// MARK: Email convenience initializers and mutators
extension Email {
convenience init(data: Data) throws {
let me = try newJSONDecoder().decode(Email.self, from: data)
self.init(sizeEstimate: me.sizeEstimate, historyID: me.historyID, threadID: me.threadID, payload: me.payload, internalDate: me.internalDate, snippet: me.snippet, id: me.id, labelIDS: me.labelIDS)
}
convenience init(_ json: String, using encoding: String.Encoding = .utf8) throws {
guard let data = json.data(using: encoding) else {
throw NSError(domain: "JSONDecoding", code: 0, userInfo: nil)
}
try self.init(data: data)
}
convenience init(fromURL url: URL) throws {
try self.init(data: try Data(contentsOf: url))
}
func with(
sizeEstimate: Int? = nil,
historyID: String? = nil,
threadID: String? = nil,
payload: Payload? = nil,
internalDate: String? = nil,
snippet: String? = nil,
id: String? = nil,
labelIDS: [String]? = nil
) -> Email {
return Email(
sizeEstimate: sizeEstimate ?? self.sizeEstimate,
historyID: historyID ?? self.historyID,
threadID: threadID ?? self.threadID,
payload: payload ?? self.payload,
internalDate: internalDate ?? self.internalDate,
snippet: snippet ?? self.snippet,
id: id ?? self.id,
labelIDS: labelIDS ?? self.labelIDS
)
}
func jsonData() throws -> Data {
return try newJSONEncoder().encode(self)
}
func jsonString(encoding: String.Encoding = .utf8) throws -> String? {
return String(data: try self.jsonData(), encoding: encoding)
}
}
// MARK: - Payload
class Payload: Codable {
let mimeType: String
let headers: [Header]
let body: Body
let partID, filename: String
enum CodingKeys: String, CodingKey {
case mimeType, headers, body
case partID = "partId"
case filename
}
init(mimeType: String, headers: [Header], body: Body, partID: String, filename: String) {
self.mimeType = mimeType
self.headers = headers
self.body = body
self.partID = partID
self.filename = filename
}
}
// MARK: Payload convenience initializers and mutators
extension Payload {
convenience init(data: Data) throws {
let me = try newJSONDecoder().decode(Payload.self, from: data)
self.init(mimeType: me.mimeType, headers: me.headers, body: me.body, partID: me.partID, filename: me.filename)
}
convenience init(_ json: String, using encoding: String.Encoding = .utf8) throws {
guard let data = json.data(using: encoding) else {
throw NSError(domain: "JSONDecoding", code: 0, userInfo: nil)
}
try self.init(data: data)
}
convenience init(fromURL url: URL) throws {
try self.init(data: try Data(contentsOf: url))
}
func with(
mimeType: String? = nil,
headers: [Header]? = nil,
body: Body? = nil,
partID: String? = nil,
filename: String? = nil
) -> Payload {
return Payload(
mimeType: mimeType ?? self.mimeType,
headers: headers ?? self.headers,
body: body ?? self.body,
partID: partID ?? self.partID,
filename: filename ?? self.filename
)
}
func jsonData() throws -> Data {
return try newJSONEncoder().encode(self)
}
func jsonString(encoding: String.Encoding = .utf8) throws -> String? {
return String(data: try self.jsonData(), encoding: encoding)
}
}
// MARK: - Body
class Body: Codable {
let size: Int
let attachmentID: String
enum CodingKeys: String, CodingKey {
case size
case attachmentID = "attachmentId"
}
init(size: Int, attachmentID: String) {
self.size = size
self.attachmentID = attachmentID
}
}
// MARK: Body convenience initializers and mutators
extension Body {
convenience init(data: Data) throws {
let me = try newJSONDecoder().decode(Body.self, from: data)
self.init(size: me.size, attachmentID: me.attachmentID)
}
convenience init(_ json: String, using encoding: String.Encoding = .utf8) throws {
guard let data = json.data(using: encoding) else {
throw NSError(domain: "JSONDecoding", code: 0, userInfo: nil)
}
try self.init(data: data)
}
convenience init(fromURL url: URL) throws {
try self.init(data: try Data(contentsOf: url))
}
func with(
size: Int? = nil,
attachmentID: String? = nil
) -> Body {
return Body(
size: size ?? self.size,
attachmentID: attachmentID ?? self.attachmentID
)
}
func jsonData() throws -> Data {
return try newJSONEncoder().encode(self)
}
func jsonString(encoding: String.Encoding = .utf8) throws -> String? {
return String(data: try self.jsonData(), encoding: encoding)
}
}
// MARK: - Header
class Header: Codable {
let name, value: String
init(name: String, value: String) {
self.name = name
self.value = value
}
}
// MARK: Header convenience initializers and mutators
extension Header {
convenience init(data: Data) throws {
let me = try newJSONDecoder().decode(Header.self, from: data)
self.init(name: me.name, value: me.value)
}
convenience init(_ json: String, using encoding: String.Encoding = .utf8) throws {
guard let data = json.data(using: encoding) else {
throw NSError(domain: "JSONDecoding", code: 0, userInfo: nil)
}
try self.init(data: data)
}
convenience init(fromURL url: URL) throws {
try self.init(data: try Data(contentsOf: url))
}
func with(
name: String? = nil,
value: String? = nil
) -> Header {
return Header(
name: name ?? self.name,
value: value ?? self.value
)
}
func jsonData() throws -> Data {
return try newJSONEncoder().encode(self)
}
func jsonString(encoding: String.Encoding = .utf8) throws -> String? {
return String(data: try self.jsonData(), encoding: encoding)
}
}
// MARK: - Helper functions for creating encoders and decoders
func newJSONDecoder() -> JSONDecoder {
let decoder = JSONDecoder()
if #available(iOS 10.0, OSX 10.12, tvOS 10.0, watchOS 3.0, *) {
decoder.dateDecodingStrategy = .iso8601
}
return decoder
}
func newJSONEncoder() -> JSONEncoder {
let encoder = JSONEncoder()
if #available(iOS 10.0, OSX 10.12, tvOS 10.0, watchOS 3.0, *) {
encoder.dateEncodingStrategy = .iso8601
}
return encoder
}
这几乎可以完美地工作;除了attachmentID
参数 - 当我尝试创建电子邮件时,我收到此错误:
keyNotFound(CodingKeys(stringValue: "attachmentId", intValue: nil), Swift.DecodingError.Context(codingPath: [CodingKeys(stringValue: "payload", intValue: nil), CodingKeys(stringValue: "body", intValue: nil)], debugDescription: "No value associated with key CodingKeys(stringValue: \"attachmentId\", intValue: nil) (\"attachmentId\").", underlyingError: nil))
在这方面我有点不知所措;所以任何帮助表示赞赏 - 我需要做些什么来确保这个属性将被分配?
编辑我忘了包括 JSON 响应;如下:
{
"snippet" : "",
"id" : "1758550e1d57a61e",
"internalDate" : "1604259323000",
"sizeEstimate" : 1811162,
"threadId" : "1758549a183c08f0",
"payload" : {
"partId" : "",
"mimeType" : "video\/mp4",
"filename" : "nicholasarner@gmail.com-2020_11_01_11_35_23-WDYT?.mp4",
"body" : {
"size" : 1322930,
"attachmentId" : "ANGjdJ_nEZvNaV972a1H9osO7Ze3WH-F5hlf8cSEQjgM9NmI8XzsKsfhAF_zV7addIHsIEgm8nmlPGID8pICD5ew8399hocuXwvfGVx_Pl3Z7f1jwgmrm1_UD6k1daGkaXFFy7kbfiiRRidy42IoKT9r3FoS4tb7mVmv7ctrQE9KvCjV2Op3MCkzvrjM494iG06yJtQhM5Zt697BG-kythaCjacFJ5cTh4c-qdCN60JIUL3sR95AWnoEvSBMVr_i6iPKIP67gpddw27MkMmqICA8jkJXXSGhGaZek2hJu886ik_3VCvqlQ4c2uypWVYNOfWMPvjVuNmlW-_MH41cSo_mqd2DaxBVkXut70bu24y2-aY50ljhVZRqhV6CSoUlbBiPEe_VxToATBy_vFLF8TZRlOGg5Jq0kleymZvRgg"
},
"headers" : [
{
"name" : "Return-Path",
"value" : "<nicholasarner@gmail.com>"
},
{
"name" : "Received",
"value" : "from iPhone ([2601:645:4200:3950:441:1411:7e85:db6d]) by smtp.gmail.com with ESMTPSA id u124sm12113464pfc.21.2020.11.01.11.35.24 for <nicholasarner@gmail.com> (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128\/128); Sun, 01 Nov 2020 11:37:51 -0800 (PST)"
},
{
"name" : "Date",
"value" : "Sun, 1 Nov 2020 11:35:23 -0800"
},
{
"name" : "From",
"value" : "nicholasarner@gmail.com"
},
{
"name" : "To",
"value" : "Nick Arner <nicholasarner@gmail.com>"
},
{
"name" : "Message-ID",
"value" : "<d5ff6514-1c55-4d98-a4d3-43a776d7b05d@iPhone>"
},
{
"name" : "In-Reply-To",
"value" : "<CAD1H43XCrKQD3omFV2ggf_e2kLm_v4234p2oHvvKGd-bJ4PZeQ@mail.gmail.com>"
},
{
"name" : "Subject",
"value" : "Re: tett"
},
{
"name" : "MIME-Version",
"value" : "1.0"
},
{
"name" : "Content-Type",
"value" : "video\/mp4"
},
{
"name" : "Content-Transfer-Encoding",
"value" : "base64"
},
{
"name" : "Content-Disposition",
"value" : "attachment; filename=\"nicholasarner@gmail.com-2020_11_01_11_35_23-WDYT?.mp4\""
}
]
},
"historyId" : "11441245",
"labelIds" : [
"IMPORTANT",
"SENT",
"INBOX"
]
}
解决方案
推荐阅读
- python - 有没有办法获取 jupyter notebook 的绝对文件路径?
- sql - 每天插入和更新 400 万条记录
- java - ModelMapper 错误地映射到嵌套对象属性
- python - 如何在不刷新的情况下正确呈现页面中数据库中的字段?
- graphql - 如何修复 EntitySchema 中一对一关系的“无法读取未定义的属性 'joinColumns'”错误
- azure-devops - 如何使用 LogicApps 等工具读取 AzureDevOps 工作项?
- sql - 使用 Python psycopg2 安排查询
- python - beautifulsoup:从字段中提取所有文本,而不是以“...”结尾的文本?
- c# - Blazor 父组件能否知道其中有多少子组件?
- javascript - Mongoose CRUD 应用程序:是否可以将收藏夹存储为静态文档和参考?