【问题标题】:How to use Codable encode with object inside object如何将 Codable 编码与对象内的对象一起使用
【发布时间】:2020-11-16 03:09:38
【问题描述】:

我正在使用我的对象负载处理 JSON 负载。但我无法在对象内编码对象。

我的 Payload 类是这样的

class ConversationPayload :BaseObject {
    var title : String? = ""
    var messageDict: MessagePayload = MessagePayload()
    var participants: [Int32] = []
    var type: String = ""
    
    enum CodingKeys: String, CodingKey {
        case title = "title"
        case messageDict = "message"
        case participants = "participants"
        case type = "type"
    }

    override func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: CodingKeys.self)
        if title != nil {
            try container.encode(title, forKey: .title)
        }
        try container.encode(messageDict, forKey: .messageDict)
        try container.encode(participants, forKey: .participants)
        try container.encode(type, forKey: .type)
    }
    
}

class MessagePayload: BaseObject {
    var body : String = ""
    var isVideocallInvite: Bool = false
    var attachmentsPayload: MessageAttachmentPayload? = nil
    
    enum CodingKeys: String, CodingKey {
        case body = "body"
        case isVideocallInvite = "is_videocall_invite"
        case attachmentsPayload = "attachment"
    }

    override func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: CodingKeys.self)
        try container.encode(body, forKey: .body)
        try container.encode(isVideocallInvite, forKey: .isVideocallInvite)
        if attachmentsPayload != nil {
            try container.encode(attachmentsPayload, forKey: .attachmentsPayload)
        }
        
    }
}

class MessageAttachmentPayload: BaseObject {
    var photo : String = ""
    var photoType : String = "jpg"
}

BaseObject 是这个

class BaseObject:Codable{}

我想在 json 有效载荷中得到的是这样的

{"message": {"body": "body_string", "is_videocall_invite": 1}, "participants" : [user-id], "type" : "converstation_type","title":"title"}

有人知道我的有效载荷类有什么问题吗?在可编码上还不是很熟悉。提前致谢。

【问题讨论】:

    标签: ios swift swift5 codable jsonencoder


    【解决方案1】:

    我不确定你在这里有什么限制,但我会简化所有这些。使 JSON 数据模型尽可能接近 JSON。

    struct ConversationJsonModel: Codable {
        var title: String?
        var message: MessageJsonModel
        var participants: [Int]
        var type: String
    }
    
    struct MessageJsonModel: Codable {
        var body: String
        var is_videocall_invite: Int
        var attachment: AttachmentJsonModel?
    }
    
    struct AttachmentJsonModel: Codable {
        var photo: String
        var photo_type: String // <-- assuming photo_type is the JSON member name.
    }
    

    如果您需要视图模型或某种其他类型的本地数据模型,那么这两个部分是分开的。

    class BaseObject {}
    
    class ConversationPayload: BaseObject {
        var title : String? = ""
        var messageDict: MessagePayload = MessagePayload()
        var participants: [Int32] = []
        var type: String = ""
    
        func makeConversationJsonModel() -> ConversationJsonModel {
            ConversationJsonModel(title: title,
                                  message: messageDict.makeMessageJsonModel(),
                                  participants: participants.map { Int($0) },
                                  type: type)
        }
    }
    
    class MessagePayload: BaseObject {
        var body : String = ""
        var isVideocallInvite: Bool = false
        var attachmentsPayload: MessageAttachmentPayload? = nil
    
        func makeMessageJsonModel() -> MessageJsonModel {
            MessageJsonModel(body: body,
                             is_videocall_invite: isVideocallInvite ? 1 : 0,
                             attachment: attachmentsPayload?.makeAttachmentJsonModel())
        }
    }
    
    class MessageAttachmentPayload: BaseObject {
        var photo : String = ""
        var photoType : String = "jpg"
    
        func makeAttachmentJsonModel() -> AttachmentJsonModel {
            AttachmentJsonModel(photo: photo, photo_type: photoType)
        }
    }
    

    最后,编码你的 JSON

    let conversationPayload = ConversationPayload()
    let json = try? JSONEncoder().encode(conversationPayload.makeConversationJsonModel())
    

    这允许 JSON 表示和有效负载模型之间的清晰分离。例如,在 JSON 中,is_videocall_invite 是一个 Int(0 或 1);同时,在有效载荷模型中,isVideocallInvite 是一个Bool

    【讨论】:

    • 感谢我注意到 is_videocall_invite 需要是 int 而不是 boolean。
    【解决方案2】:

    有什么问题?我刚刚测试了你的课程,它有一些小问题,但它确实符合可编码并且它编码没有问题。

    在操场上:

    var conversation = ConversationPayload()
    var message = MessagePayload()
    message.body = "message body"
    message.isVideocallInvite = true
    var attachment = MessageAttachmentPayload()
    attachment.photo = "attachment_file"
    message.attachmentsPayload = attachment
    conversation.messageDict = message
    conversation.title = "Title"
    conversation.participants = [1, 2, 3, 4]
    conversation.type = "Conversation Type"
    
    let encoder = JSONEncoder()
    encoder.outputFormatting = .prettyPrinted
    let data = try! encoder.encode(conversation)
    print(String(data: data, encoding: .utf8)!)
    

    输出如下所示:

    {
      "participants" : [
        1,
        2,
        3,
        4
      ],
      "message" : {
        "is_videocall_invite" : true,
        "attachment" : {
          "photo" : "attachment_file",
          "photoType" : "jpg"
        },
        "body" : "message body"
      },
      "title" : "Title",
      "type" : "Conversation Type"
    }
    

    我在MessageAttachmentPayload 类中添加了encodeCodingKey 来对值进行编码。

    这不是你所期待的吗?

    【讨论】:

    • 我看到了错误。 API 在 is_videocall_invite 上需要一个整数 (1,0),所以我将它从 bool 更改为 int。感谢您的回复
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-09-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-04
    • 2016-05-24
    • 2012-05-21
    相关资源
    最近更新 更多