You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Swift解码ChatReceivedMessageModel遇keyNotFound("userFullName")错误求助

解码ChatReceivedMessageModel时出现CodingKeys错误

我尝试在listenDeleted()方法中获取并解码数据,能接收到数据,但解码时触发CodingKeys错误。

监听方法代码

func listenDeleted() {
    socket?.off("deletedmessage")
    socket?.on("deletedmessage") { data, ack in
        let messageDict = data.last as! NSDictionary
        let messageDataObject = try? JSONSerialization.data(withJSONObject: messageDict, options: [])
        guard let messageData = messageDataObject else { return }
        do {
            let jsonDecoder = JSONDecoder()
            let message = try jsonDecoder.decode(ChatReceivedMessageModel.self, from: messageData)
            print("success")
            let messageID = message.messageId ?? ""
            let usertoConnect = message.userToConnect ?? ""
            let room = message.room ?? ""
            let userInfo = ["messageId": messageID]
            NotificationCenter.default.post(name: Notification.Name("messageDeleted"), object: nil, userInfo: userInfo)
        } catch {
            print("Unexpected error: \(error).")
        }
    }
}

模型代码

class ChatReceivedMessageModel: Serializable {
var room: String?
var message: String?
var userToConnect: String?
var userFullName: String?
var senderId: String?
var senderPhotoUrl: String?
var creationTimestamp: Int64?
var messageId: String?

init(room: String, message: String, userToConnect: String, userFullName: String, senderId: String, senderPhotoUrl: String, creationTimestamp: Int64, messageId: String) {
    self.room = room
    self.message = message
    self.userToConnect = userToConnect
    self.userFullName = userFullName
    self.senderId = senderId
    self.senderPhotoUrl = senderPhotoUrl
    self.creationTimestamp = creationTimestamp
    self.messageId = messageId
}

enum CodingKeys: String, CodingKey {
    case room
    case message
    case userToConnect
    case userFullName
    case senderId
    case senderPhotoUrl
    case creationTimestamp
    case messageId
}

required init(from decoder: Decoder) throws {
    let values = try decoder.container(keyedBy: CodingKeys.self)
    room = try values.decode(String.self, forKey: .room)
    message = try values.decodeIfPresent(String.self, forKey: .message)
    userToConnect = try values.decode(String.self, forKey: .userToConnect)
    userFullName = try values.decode(String.self, forKey: .userFullName)
    senderId =  try values.decode(String.self, forKey: .senderId)
    senderPhotoUrl = try values.decode(String.self, forKey: .senderPhotoUrl)
    creationTimestamp = try values.decode(Int64.self, forKey: .creationTimestamp)
    messageId = try values.decode(String.self, forKey: .messageId)
}

func encode(to encoder: Encoder) throws {
    var container = encoder.container(keyedBy: CodingKeys.self)
    try container.encode(room, forKey: .room)
    try container.encode(message, forKey: .message)
    try container.encode(userToConnect, forKey: .userToConnect)
    try container.encode(userFullName, forKey: .userFullName)
    try container.encode(senderId, forKey: .senderId)
    try container.encode(senderPhotoUrl, forKey: .senderPhotoUrl)
    try container.encode(creationTimestamp, forKey: .creationTimestamp)
    try container.encode(messageId, forKey: .messageId)
}

func getChatUserModelType() -> ChatUserModel {
    var model = ChatUserModel()
    model.communityUserId = self.senderId
    model.name = self.userFullName
    model.photoUrl = self.senderPhotoUrl
    return model
  }
}

报错信息

Unexpected error: keyNotFound(CodingKeys(stringValue: "userFullName", intValue: nil), Swift.DecodingError.Context(codingPath: [], debugDescription: "No value associated with key CodingKeys(stringValue: "userFullName", intValue: nil) ("userFullName").", underlyingError: nil)).

断点截图显示的数据

断点截图


解决方案

问题出在模型的解码逻辑:返回的JSON中仅包含room、messageId、userToConnect三个字段,但解码方法里对userFullName、senderId等字段使用了强制解析的decode(_:forKey:),当JSON中没有对应键时就会抛出keyNotFound错误。

修改模型的init(from decoder:)方法,将所有非必填字段的解析替换为decodeIfPresent(_:forKey:),这样即使字段不存在也只会赋值为nil,不会触发错误:

required init(from decoder: Decoder) throws {
    let values = try decoder.container(keyedBy: CodingKeys.self)
    room = try values.decodeIfPresent(String.self, forKey: .room)
    message = try values.decodeIfPresent(String.self, forKey: .message)
    userToConnect = try values.decodeIfPresent(String.self, forKey: .userToConnect)
    userFullName = try values.decodeIfPresent(String.self, forKey: .userFullName)
    senderId = try values.decodeIfPresent(String.self, forKey: .senderId)
    senderPhotoUrl = try values.decodeIfPresent(String.self, forKey: .senderPhotoUrl)
    creationTimestamp = try values.decodeIfPresent(Int64.self, forKey: .creationTimestamp)
    messageId = try values.decodeIfPresent(String.self, forKey: .messageId)
}

另外,由于你的模型属性都是可选类型(String?/Int64?),使用decodeIfPresent完全匹配属性的可选语义,同时也符合删除消息通知仅携带必要字段的场景。


内容的提问来源于stack exchange,提问作者Mert Köksal

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.22 20:19:01