我如何找出编码路径中的哪个元素导致了 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 告诉解码器将所有只有一个父项(不是 countconversation_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))