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

Swift中Pubnub消息含项目类名,自动序列化解码失效问题

问题描述

我尝试通过Pubnub发送自定义的JSON数据,官方文档说明无需手动序列化,Pubnub会自动完成该操作。我定义的数据结构如下:

struct CanvasData { 
    var previousX: CGFloat 
    var previousY: CGFloat 
    var currentX: CGFloat 
    var currentY: CGFloat 
    var isStylus: Bool 
    var force: CGFloat 
    var radius: CGFloat 
} 
struct WhiteboardDataModel { 
    var points: [CanvasData] 
}

发送数据的代码为:

client.publish(data, toChannel: "whiteboard-hack", withCompletion: nil)

其中data是WhiteboardDataModel类型的实例。但接收消息时,返回内容包含项目文件名和类名,示例如下:

Optional(apple_pencil_poc.WhiteboardDataModel(points[apple_pencil_poc.CanvasData(previousX: 717.5, previousY: 378.5, currentX: 717.5, currentY: 378.5, isStylus: true, force: 0.333333333333333, radius: 0.25),apple_pencil_poc.CanvasData(previousX: 717.5, previousY: 378.5, currentX: 717.5, currentY: 378.5, ..etc )

想知道为何会出现这种情况,以及该如何解码这类数据,恳请相关建议。


原因分析

出现这个问题的核心原因是你的自定义结构体没有遵循Swift的Codable协议。虽然Pubnub声称自动处理序列化,但它实际上依赖于Swift的Codable(或旧的NSCoding)来将对象转换为标准JSON。如果结构体没有实现Codable,Pubnub会默认使用Swift的CustomStringConvertible默认实现——也就是输出对象的调试描述,这就导致你看到的包含项目模块名、类名的字符串格式,而非真正的JSON结构。


解决方法

1. 让结构体遵循Codable协议

只需要给两个结构体添加Codable协议即可,因为你结构体里的所有属性(CGFloat、Bool)都默认支持Codable,不需要手动实现编码和解码逻辑:

struct CanvasData: Codable { 
    var previousX: CGFloat 
    var previousY: CGFloat 
    var currentX: CGFloat 
    var currentY: CGFloat 
    var isStylus: Bool 
    var force: CGFloat 
    var radius: CGFloat 
} 
struct WhiteboardDataModel: Codable { 
    var points: [CanvasData] 
}

这样Pubnub就能正确将你的对象序列化为标准JSON格式,接收端也能拿到正常的JSON数据。

2. 接收端解码数据

如果接收端也是Swift项目,可以直接用JSONDecoder解码收到的数据:

// 假设收到的消息内容为Data类型
do {
    let whiteboardData = try JSONDecoder().decode(WhiteboardDataModel.self, from: receivedData)
    // 正常使用解码后的whiteboardData
} catch {
    print("解码失败:\(error)")
}

如果接收端是其他语言(比如JavaScript),会收到标准的JSON对象,可直接解析使用。

3. 额外注意事项

  • 如果结构体包含自定义类型,需要确保这些类型也遵循Codable协议。
  • 若需要自定义JSON键名(比如把previousX改成prev_x),可以通过CodingKeys枚举映射:
struct CanvasData: Codable { 
    var previousX: CGFloat 
    var previousY: CGFloat 
    // ...其他属性
    
    enum CodingKeys: String, CodingKey {
        case previousX = "prev_x"
        case previousY = "prev_y"
        // ...对应其他属性的键名
    }
}

内容的提问来源于stack exchange,提问作者Kex

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 06:52:27