如何找出编码路径中的哪个元素正导致Swift解码错误?

问题描述

我正在调用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
    }
}

最后,是我的getChatMessages函数返回的ConversationDetails对象的结构

class ConversationDetails: Codable {
    
    var messages: [ChatMessage]?
    var conversation_participants: [ConversationParticipants]?
}

以下是来自getChatMessages API调用的响应:

enter image description here

问题:我收到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))