我如何找出编码路径中的哪个元素导致了 Swift 解码错误?
How can I find out which element in the coding path exactly is causing a Swift Decoding error?
我正在调用一个 API 端点 getChatMessages 并将响应解码如下:
func getChatMessages(conversation: Int, pagesize: Int = 10, page: Int = 1, completion: @escaping(Result<ConversationDetails, APIError>) -> Void) {
{...some networking - configure request and start dataTask}
do {
let dateFormatter: DateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .formatted(dateFormatter)
decoder.keyDecodingStrategy = .custom { codingKeys in
let lastKey = codingKeys.last!
if lastKey.intValue != nil || codingKeys.count != 2 { return lastKey }
if lastKey.stringValue == "count" || lastKey.stringValue == "conversation_participants" { return lastKey }
return AnyCodingKey(stringValue: "element")!
}
let result = try decoder.decode(ResponseMultipleElements<ConversationDetails>.self, from: data!)
completion(.success(result.detailresponse.element))
}catch {
print("Error is: ", error)
completion(.failure(.decodingError))
}
}
dataTask.resume()
}
这是 ResponseMultipleElements 结构
struct ResponseMultipleElements<T1: Decodable>: Decodable {
let statuscode: Int
let response_type: Int
let errormessage: String?
let detailresponse: Element<T1>
}
struct Element<T2: Decodable>: Decodable {
let count: Int
let element: T2
let conversation_participants: [ConversationParticipants]?
}
struct AnyCodingKey: CodingKey {
var stringValue: String
init?(stringValue: String) {
self.stringValue = stringValue
}
var intValue: Int? { return nil }
init?(intValue: Int) {
return nil
}
}
最后,ConversationDetails 对象的结构,由我的 getChatMessages 函数返回
class ConversationDetails: Codable {
var messages: [ChatMessage]?
var conversation_participants: [ConversationParticipants]?
}
getChatMessages API 调用的响应如下所示:
问题:我得到 typeMismatch(Swift.Dictionary<Swift.String, Any>, Swift.DecodingError.Context(codingPath: [CodingKeys(stringValue: "detailresponse", intValue: nil), CodingKeys(stringValue: "element", intValue: nil)], debugDescription: "Expected to decode Dictionary<String, Any> but found an array instead.", underlyingError: nil))
现在遍历了所有内容,但找不到错误。
我不确定它为哪个元素找到了一个数组而不是预期的 所以不知道要修复什么。希望有人能帮忙。
您的 keyDecodingStrategy
告诉解码器将所有只有一个父项(不是 count
或 conversation_participants
)的字符串键视为“元素”。在您的 JSON 中只有一个这样的密钥满足此条件 - messages
,在 detailresponse
.
下
messages
密钥将被解码为:
let element: T2
其中 T2
是:
class ConversationDetails: Codable {
var messages: [ChatMessage]?
var conversation_participants: [ConversationParticipants]?
}
但是messages
实际上是一个数组在JSON!
我建议你解码一个ResponseMultipleElements<[ChatMessage]?>
。这样,T2
实际上就是预期的数组类型。
您应该向 ConversationDetails
添加一个初始化程序,以允许您从一组聊天消息和参与者中创建一个 ConversationDetails
,
init(messages: [ChatMessage]?, conversation_participants: [ConversationParticipants]?) {
self.messages = messages
self.conversation_participants = conversation_participants
}
并在getChatMessages
中使用它:
let result = try decoder.decode(ResponseMultipleElements<[ChatMessage]?>.self, from: data!)
let convoDetails = ConversationDetails(
messages: result.detailresponse.element,
conversation_participants: result.detailresponse.conversation_participants
)
completion(.success(convoDetails))
我正在调用一个 API 端点 getChatMessages 并将响应解码如下:
func getChatMessages(conversation: Int, pagesize: Int = 10, page: Int = 1, completion: @escaping(Result<ConversationDetails, APIError>) -> Void) {
{...some networking - configure request and start dataTask}
do {
let dateFormatter: DateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .formatted(dateFormatter)
decoder.keyDecodingStrategy = .custom { codingKeys in
let lastKey = codingKeys.last!
if lastKey.intValue != nil || codingKeys.count != 2 { return lastKey }
if lastKey.stringValue == "count" || lastKey.stringValue == "conversation_participants" { return lastKey }
return AnyCodingKey(stringValue: "element")!
}
let result = try decoder.decode(ResponseMultipleElements<ConversationDetails>.self, from: data!)
completion(.success(result.detailresponse.element))
}catch {
print("Error is: ", error)
completion(.failure(.decodingError))
}
}
dataTask.resume()
}
这是 ResponseMultipleElements 结构
struct ResponseMultipleElements<T1: Decodable>: Decodable {
let statuscode: Int
let response_type: Int
let errormessage: String?
let detailresponse: Element<T1>
}
struct Element<T2: Decodable>: Decodable {
let count: Int
let element: T2
let conversation_participants: [ConversationParticipants]?
}
struct AnyCodingKey: CodingKey {
var stringValue: String
init?(stringValue: String) {
self.stringValue = stringValue
}
var intValue: Int? { return nil }
init?(intValue: Int) {
return nil
}
}
最后,ConversationDetails 对象的结构,由我的 getChatMessages 函数返回
class ConversationDetails: Codable {
var messages: [ChatMessage]?
var conversation_participants: [ConversationParticipants]?
}
getChatMessages API 调用的响应如下所示:
问题:我得到 typeMismatch(Swift.Dictionary<Swift.String, Any>, Swift.DecodingError.Context(codingPath: [CodingKeys(stringValue: "detailresponse", intValue: nil), CodingKeys(stringValue: "element", intValue: nil)], debugDescription: "Expected to decode Dictionary<String, Any> but found an array instead.", underlyingError: nil))
现在遍历了所有内容,但找不到错误。
我不确定它为哪个元素找到了一个数组而不是预期的
您的 keyDecodingStrategy
告诉解码器将所有只有一个父项(不是 count
或 conversation_participants
)的字符串键视为“元素”。在您的 JSON 中只有一个这样的密钥满足此条件 - messages
,在 detailresponse
.
messages
密钥将被解码为:
let element: T2
其中 T2
是:
class ConversationDetails: Codable {
var messages: [ChatMessage]?
var conversation_participants: [ConversationParticipants]?
}
但是messages
实际上是一个数组在JSON!
我建议你解码一个ResponseMultipleElements<[ChatMessage]?>
。这样,T2
实际上就是预期的数组类型。
您应该向 ConversationDetails
添加一个初始化程序,以允许您从一组聊天消息和参与者中创建一个 ConversationDetails
,
init(messages: [ChatMessage]?, conversation_participants: [ConversationParticipants]?) {
self.messages = messages
self.conversation_participants = conversation_participants
}
并在getChatMessages
中使用它:
let result = try decoder.decode(ResponseMultipleElements<[ChatMessage]?>.self, from: data!)
let convoDetails = ConversationDetails(
messages: result.detailresponse.element,
conversation_participants: result.detailresponse.conversation_participants
)
completion(.success(convoDetails))